[feature] Enable basic video support (mp4 only) (#1274)

* [feature] basic video support

* fix missing semicolon

* replace text shadow with stacked icons

Co-authored-by: f0x <f0x@cthu.lu>
This commit is contained in:
tobi
2022-12-17 05:38:56 +01:00
committed by GitHub
parent 0f38e7c9b0
commit 2bbc64be43
39 changed files with 6276 additions and 93 deletions

View File

@@ -88,11 +88,11 @@ func (p *ProcessingMedia) LoadAttachment(ctx context.Context) (*gtsmodel.MediaAt
return nil, err
}
if err := p.loadThumb(ctx); err != nil {
if err := p.loadFullSize(ctx); err != nil {
return nil, err
}
if err := p.loadFullSize(ctx); err != nil {
if err := p.loadThumb(ctx); err != nil {
return nil, err
}
@@ -128,7 +128,6 @@ func (p *ProcessingMedia) loadThumb(ctx context.Context) error {
switch processState(thumbState) {
case received:
// we haven't processed a thumbnail for this media yet so do it now
// check if we need to create a blurhash or if there's already one set
var createBlurhash bool
if p.attachment.Blurhash == "" {
@@ -136,27 +135,46 @@ func (p *ProcessingMedia) loadThumb(ctx context.Context) error {
createBlurhash = true
}
// stream the original file out of storage
stored, err := p.storage.GetStream(ctx, p.attachment.File.Path)
if err != nil {
p.err = fmt.Errorf("loadThumb: error fetching file from storage: %s", err)
var (
thumb *mediaMeta
err error
)
switch ct := p.attachment.File.ContentType; ct {
case mimeImageJpeg, mimeImagePng, mimeImageWebp, mimeImageGif:
// thumbnail the image from the original stored full size version
stored, err := p.storage.GetStream(ctx, p.attachment.File.Path)
if err != nil {
p.err = fmt.Errorf("loadThumb: error fetching file from storage: %s", err)
atomic.StoreInt32(&p.thumbState, int32(errored))
return p.err
}
thumb, err = deriveThumbnailFromImage(stored, ct, createBlurhash)
// try to close the stored stream we had open, no matter what
if closeErr := stored.Close(); closeErr != nil {
log.Errorf("error closing stream: %s", closeErr)
}
// now check if we managed to get a thumbnail
if err != nil {
p.err = fmt.Errorf("loadThumb: error deriving thumbnail: %s", err)
atomic.StoreInt32(&p.thumbState, int32(errored))
return p.err
}
case mimeVideoMp4:
// create a generic thumbnail based on video height + width
thumb, err = deriveThumbnailFromVideo(p.attachment.FileMeta.Original.Height, p.attachment.FileMeta.Original.Width)
if err != nil {
p.err = fmt.Errorf("loadThumb: error deriving thumbnail: %s", err)
atomic.StoreInt32(&p.thumbState, int32(errored))
return p.err
}
default:
p.err = fmt.Errorf("loadThumb: content type %s not a processible image type", ct)
atomic.StoreInt32(&p.thumbState, int32(errored))
return p.err
}
defer stored.Close()
// stream the file from storage straight into the derive thumbnail function
thumb, err := deriveThumbnail(stored, p.attachment.File.ContentType, createBlurhash)
if err != nil {
p.err = fmt.Errorf("loadThumb: error deriving thumbnail: %s", err)
atomic.StoreInt32(&p.thumbState, int32(errored))
return p.err
}
// Close stored media now we're done
if err := stored.Close(); err != nil {
log.Errorf("loadThumb: error closing stored full size: %s", err)
}
// put the thumbnail in storage
if err := p.storage.Put(ctx, p.attachment.Thumbnail.Path, thumb.small); err != nil && err != storage.ErrAlreadyExists {
@@ -195,7 +213,7 @@ func (p *ProcessingMedia) loadFullSize(ctx context.Context) error {
switch processState(fullSizeState) {
case received:
var err error
var decoded *imageMeta
var decoded *mediaMeta
// stream the original file out of storage...
stored, err := p.storage.GetStream(ctx, p.attachment.File.Path)
@@ -218,6 +236,8 @@ func (p *ProcessingMedia) loadFullSize(ctx context.Context) error {
decoded, err = decodeImage(stored, ct)
case mimeImageGif:
decoded, err = decodeGif(stored)
case mimeVideoMp4:
decoded, err = decodeVideo(stored, ct)
default:
err = fmt.Errorf("loadFullSize: content type %s not a processible image type", ct)
}
@@ -295,7 +315,7 @@ func (p *ProcessingMedia) store(ctx context.Context) error {
}
// bail if this is a type we can't process
if !supportedImage(contentType) {
if !supportedAttachment(contentType) {
return fmt.Errorf("store: media type %s not (yet) supported", contentType)
}
@@ -338,6 +358,10 @@ func (p *ProcessingMedia) store(ctx context.Context) error {
// can't terminate if we don't know the file size, so just store the multiReader
readerToStore = multiReader
}
case mimeMp4:
p.attachment.Type = gtsmodel.FileTypeVideo
// nothing to terminate, we can just store the multireader
readerToStore = multiReader
default:
return fmt.Errorf("store: couldn't process %s", extension)
}