1
Fork 0

Don't transcode web compatible video formats.

This relates to the following issues #131 #169 #173
This commit is contained in:
viktorstrate 2021-01-27 18:00:37 +01:00
parent 404f1898c2
commit fbebb13d28
No known key found for this signature in database
GPG Key ID: 3F855605109C1E8A
5 changed files with 91 additions and 25 deletions

View File

@ -17,14 +17,14 @@ type Media struct {
AlbumID int `gorm:"not null;index"`
Album Album `gorm:"constraint:OnDelete:CASCADE;"`
ExifID *int `gorm:"index"`
Exif *MediaEXIF `gorm:"constraint:OnDelete:SET NULL;"`
Exif *MediaEXIF `gorm:"constraint:OnDelete:CASCADE;"`
MediaURL []MediaURL `gorm:"constraint:OnDelete:CASCADE;"`
DateShot time.Time `gorm:"not null"`
DateImported time.Time `gorm:"not null"`
// Favorite bool `gorm:"not null, default:false"`
Type MediaType `gorm:"not null;index"`
VideoMetadataID *int `gorm:"index"`
VideoMetadata *VideoMetadata `gorm:"constraint:OnDelete:SET NULL;"`
VideoMetadata *VideoMetadata `gorm:"constraint:OnDelete:CASCADE;"`
SideCarPath *string
SideCarHash *string `gorm:"unique"`

View File

@ -185,7 +185,7 @@ func (r *mediaResolver) VideoWeb(ctx context.Context, media *models.Media) (*mod
var url models.MediaURL
err := r.Database.
Where("media_id = ?", media.ID).
Where("purpose = ?", models.VideoWeb).
Where("purpose = ? OR purpose = ?", models.VideoWeb, models.MediaOriginal).
First(&url).Error
if err != nil {

View File

@ -58,7 +58,7 @@ const (
TypeMPEG MediaType = "video/mpeg"
Type3GP MediaType = "video/3gpp"
Type3G2 MediaType = "video/3gpp2"
TypeOGV MediaType = "video/ogg"
TypeOGG MediaType = "video/ogg"
TypeWMV MediaType = "video/x-ms-wmv"
TypeAVI MediaType = "video/x-msvideo"
TypeWEBM MediaType = "video/webm"
@ -120,7 +120,7 @@ var VideoMimetypes = [...]MediaType{
TypeMPEG,
Type3GP,
Type3G2,
TypeOGV,
TypeOGG,
TypeWMV,
TypeAVI,
TypeWEBM,
@ -129,6 +129,14 @@ var VideoMimetypes = [...]MediaType{
TypeMTS,
}
// WebVideoMimetypes are video types that can be played directly in the browser without transcoding
var WebVideoMimetypes = [...]MediaType{
TypeMP4,
TypeMPEG,
TypeWEBM,
TypeOGG,
}
var fileExtensions = map[string]MediaType{
".jpg": TypeJpeg,
".jpeg": TypeJpeg,
@ -167,7 +175,7 @@ var fileExtensions = map[string]MediaType{
".mpeg": TypeMPEG,
".3gp": Type3GP,
".3g2": Type3G2,
".ogv": TypeOGV,
".ogv": TypeOGG,
".wmv": TypeWMV,
".avi": TypeAVI,
".webm": TypeWEBM,
@ -195,6 +203,12 @@ func (imgType *MediaType) isWebCompatible() bool {
}
}
for _, web_mime := range WebVideoMimetypes {
if web_mime == *imgType {
return true
}
}
return false
}

View File

@ -40,6 +40,25 @@ func makePhotoURLChecker(tx *gorm.DB, mediaID int) func(purpose models.MediaPurp
}
}
func generateUniqueMediaNamePrefixed(prefix string, mediaPath string, extension string) string {
mediaName := fmt.Sprintf("%s_%s_%s", prefix, path.Base(mediaPath), utils.GenerateToken())
mediaName = models.SanitizeMediaName(mediaName)
mediaName = mediaName + extension
return mediaName
}
func generateUniqueMediaName(mediaPath string) string {
filename := path.Base(mediaPath)
baseName := filename[0 : len(filename)-len(path.Ext(filename))]
baseExt := path.Ext(filename)
mediaName := fmt.Sprintf("%s_%s", baseName, utils.GenerateToken())
mediaName = models.SanitizeMediaName(mediaName) + baseExt
return mediaName
}
func ProcessMedia(tx *gorm.DB, media *models.Media) (bool, error) {
imageData := EncodeMediaData{
media: media,
@ -110,13 +129,11 @@ func processPhoto(tx *gorm.DB, imageData *EncodeMediaData, photoCachePath *strin
if !contentType.isWebCompatible() {
didProcess = true
highres_name := fmt.Sprintf("highres_%s_%s", path.Base(photo.Path), utils.GenerateToken())
highres_name = models.SanitizeMediaName(highres_name)
highres_name = highres_name + ".jpg"
highresName := generateUniqueMediaNamePrefixed("highres", photo.Path, ".jpg")
baseImagePath = path.Join(*photoCachePath, highres_name)
baseImagePath = path.Join(*photoCachePath, highresName)
newHighResURL, err := generateSaveHighResJPEG(tx, photo, imageData, highres_name, baseImagePath, nil)
newHighResURL, err := generateSaveHighResJPEG(tx, photo, imageData, highresName, baseImagePath, nil)
if err != nil {
return false, err
}
@ -159,11 +176,9 @@ func processPhoto(tx *gorm.DB, imageData *EncodeMediaData, photoCachePath *strin
if thumbURL == nil {
didProcess = true
thumbnail_name := fmt.Sprintf("thumbnail_%s_%s", path.Base(photo.Path), utils.GenerateToken())
thumbnail_name = models.SanitizeMediaName(thumbnail_name)
thumbnail_name = thumbnail_name + ".jpg"
thumbnailName := generateUniqueMediaNamePrefixed("thumbnail", photo.Path, ".jpg")
newThumbURL, err := generateSaveThumbnailJPEG(tx, photo, thumbnail_name, photoCachePath, baseImagePath, nil)
newThumbURL, err := generateSaveThumbnailJPEG(tx, photo, thumbnailName, photoCachePath, baseImagePath, nil)
if err != nil {
return false, err
}
@ -228,12 +243,7 @@ func makeMediaCacheDir(media *models.Media) (*string, error) {
}
func saveOriginalPhotoToDB(tx *gorm.DB, photo *models.Media, imageData *EncodeMediaData, photoDimensions *PhotoDimensions) error {
photoName := path.Base(photo.Path)
photoBaseName := photoName[0 : len(photoName)-len(path.Ext(photoName))]
photoBaseExt := path.Ext(photoName)
original_image_name := fmt.Sprintf("%s_%s", photoBaseName, utils.GenerateToken())
original_image_name = models.SanitizeMediaName(original_image_name) + photoBaseExt
originalImageName := generateUniqueMediaName(photo.Path)
contentType, err := imageData.ContentType()
if err != nil {
@ -247,7 +257,7 @@ func saveOriginalPhotoToDB(tx *gorm.DB, photo *models.Media, imageData *EncodeMe
mediaURL := models.MediaURL{
Media: *photo,
MediaName: original_image_name,
MediaName: originalImageName,
Width: photoDimensions.Width,
Height: photoDimensions.Height,
Purpose: models.MediaOriginal,
@ -256,7 +266,7 @@ func saveOriginalPhotoToDB(tx *gorm.DB, photo *models.Media, imageData *EncodeMe
}
if err := tx.Create(&mediaURL).Error; err != nil {
return errors.Wrapf(err, "inserting original photo url: %d, %s", photo.ID, photoName)
return errors.Wrapf(err, "inserting original photo url: %d, %s", photo.ID, photo.Title)
}
return nil

View File

@ -9,9 +9,9 @@ import (
"strings"
"time"
"github.com/pkg/errors"
"github.com/photoview/photoview/api/graphql/models"
"github.com/photoview/photoview/api/utils"
"github.com/pkg/errors"
"gopkg.in/vansante/go-ffprobe.v2"
"gorm.io/gorm"
)
@ -24,6 +24,11 @@ func processVideo(tx *gorm.DB, mediaData *EncodeMediaData, videoCachePath *strin
mediaURLFromDB := makePhotoURLChecker(tx, video.ID)
videoOriginalURL, err := mediaURLFromDB(models.MediaOriginal)
if err != nil {
return false, errors.Wrap(err, "error processing video original format")
}
videoWebURL, err := mediaURLFromDB(models.VideoWeb)
if err != nil {
return false, errors.Wrap(err, "error processing video web-format")
@ -34,7 +39,44 @@ func processVideo(tx *gorm.DB, mediaData *EncodeMediaData, videoCachePath *strin
return false, errors.Wrap(err, "error processing video thumbnail")
}
if videoWebURL == nil {
videoType, err := mediaData.ContentType()
if err != nil {
return false, errors.Wrap(err, "error getting video content type")
}
if videoOriginalURL == nil && videoType.isWebCompatible() {
didProcess = true
origVideoPath := video.Path
videoMediaName := generateUniqueMediaName(video.Path)
webMetadata, err := readVideoStreamMetadata(origVideoPath)
if err != nil {
return false, errors.Wrapf(err, "failed to read metadata for original video (%s)", video.Title)
}
fileStats, err := os.Stat(origVideoPath)
if err != nil {
return false, errors.Wrap(err, "reading file stats of original video")
}
mediaURL := models.MediaURL{
MediaID: video.ID,
MediaName: videoMediaName,
Width: webMetadata.Width,
Height: webMetadata.Height,
Purpose: models.MediaOriginal,
ContentType: string(*videoType),
FileSize: fileStats.Size(),
}
if err := tx.Create(&mediaURL).Error; err != nil {
return false, errors.Wrapf(err, "failed to insert original video into database (%s)", video.Title)
}
}
if videoWebURL == nil && !videoType.isWebCompatible() {
didProcess = true
web_video_name := fmt.Sprintf("web_video_%s_%s", path.Base(video.Path), utils.GenerateToken())