Don't transcode web compatible video formats.
This relates to the following issues #131 #169 #173
This commit is contained in:
parent
404f1898c2
commit
fbebb13d28
|
@ -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"`
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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())
|
||||
|
|
Loading…
Reference in New Issue