mirror of
https://github.com/photoprism/photoprism.git
synced 2025-12-12 00:34:13 +01:00
Media: Refactor video content type constants #4770
Signed-off-by: Michael Mayer <michael@photoprism.app>
This commit is contained in:
@@ -128,6 +128,6 @@ func AbortVideo(c *gin.Context) {
|
||||
|
||||
func AbortVideoWithStatus(c *gin.Context, code int) {
|
||||
if c != nil {
|
||||
c.Data(code, header.ContentTypeMp4Avc720, brokenVideo)
|
||||
c.Data(code, header.ContentTypeMp4AvcMain, brokenVideo)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -153,7 +153,7 @@ func GetVideo(router *gin.RouterGroup) {
|
||||
|
||||
if avcFile, avcErr := conv.ToAvc(mediaFile, get.Config().FFmpegEncoder(), false, false); avcFile != nil && avcErr == nil {
|
||||
videoFileName = avcFile.FileName()
|
||||
AddContentTypeHeader(c, header.ContentTypeMp4Avc)
|
||||
AddContentTypeHeader(c, header.ContentTypeMp4AvcHigh)
|
||||
} else {
|
||||
// Log error and default to 404.mp4
|
||||
log.Errorf("video: failed to transcode %s", clean.Log(f.FileName))
|
||||
|
||||
@@ -15,9 +15,9 @@ import (
|
||||
|
||||
func TestGetVideo(t *testing.T) {
|
||||
t.Run("ContentTypeAVC", func(t *testing.T) {
|
||||
assert.Equal(t, header.ContentTypeMp4Avc, clean.ContentType("video/mp4; codecs=\"avc1\""))
|
||||
assert.Equal(t, header.ContentTypeMp4AvcHigh, clean.ContentType("video/mp4; codecs=\"avc1\""))
|
||||
mimeType := fmt.Sprintf("video/mp4; codecs=\"%s\"", clean.Codec("avc1"))
|
||||
assert.Equal(t, header.ContentTypeMp4Avc, video.ContentType(mimeType, "mp4", "avc1"))
|
||||
assert.Equal(t, header.ContentTypeMp4AvcHigh, video.ContentType(mimeType, "mp4", "avc1"))
|
||||
})
|
||||
|
||||
t.Run("NoHash", func(t *testing.T) {
|
||||
|
||||
@@ -886,7 +886,7 @@ func TestFile_ContentType(t *testing.T) {
|
||||
t.Run("Video", func(t *testing.T) {
|
||||
avc := FileFixtures.Get("Video.mp4")
|
||||
assert.Equal(t, true, avc.FileVideo)
|
||||
assert.Equal(t, header.ContentTypeMp4Avc, avc.ContentType())
|
||||
assert.Equal(t, header.ContentTypeMp4AvcHigh, avc.ContentType())
|
||||
hevc := FileFixtures.Get("Photo21.mp4")
|
||||
assert.Equal(t, true, hevc.FileVideo)
|
||||
assert.Equal(t, header.ContentTypeMp4Hevc, hevc.ContentType())
|
||||
|
||||
@@ -181,7 +181,7 @@ func TestPhoto_MediaInfo(t *testing.T) {
|
||||
{
|
||||
FileVideo: true,
|
||||
MediaType: media.Video.String(),
|
||||
FileMime: header.ContentTypeMp4Avc,
|
||||
FileMime: header.ContentTypeMp4AvcHigh,
|
||||
FileCodec: video.CodecAvc,
|
||||
FileHash: "53c89dcfa006c9e592dd9e6db4b31cd57be64b81",
|
||||
},
|
||||
@@ -193,7 +193,7 @@ func TestPhoto_MediaInfo(t *testing.T) {
|
||||
mediaHash, mediaCodec, mediaMime := r.MediaInfo()
|
||||
assert.Equal(t, "53c89dcfa006c9e592dd9e6db4b31cd57be64b81", mediaHash)
|
||||
assert.Equal(t, video.CodecAvc, mediaCodec)
|
||||
assert.Equal(t, header.ContentTypeMp4Avc, mediaMime)
|
||||
assert.Equal(t, header.ContentTypeMp4AvcHigh, mediaMime)
|
||||
})
|
||||
t.Run("VideoCodecHVC", func(t *testing.T) {
|
||||
r := Photo{
|
||||
@@ -216,7 +216,7 @@ func TestPhoto_MediaInfo(t *testing.T) {
|
||||
{
|
||||
FileVideo: true,
|
||||
MediaType: media.Video.String(),
|
||||
FileMime: header.ContentTypeMp4Avc,
|
||||
FileMime: header.ContentTypeMp4AvcHigh,
|
||||
FileCodec: "xyz",
|
||||
FileHash: "",
|
||||
},
|
||||
@@ -231,7 +231,7 @@ func TestPhoto_MediaInfo(t *testing.T) {
|
||||
FileVideo: true,
|
||||
MediaType: media.Video.String(),
|
||||
FileCodec: video.CodecAvc,
|
||||
FileMime: header.ContentTypeMp4Avc,
|
||||
FileMime: header.ContentTypeMp4AvcHigh,
|
||||
FileHash: "ddb3f44eb500d7669cbe0a95e66d5a63f642487d",
|
||||
},
|
||||
},
|
||||
@@ -259,7 +259,7 @@ func TestPhoto_MediaInfo(t *testing.T) {
|
||||
{
|
||||
FileVideo: true,
|
||||
MediaType: media.Video.String(),
|
||||
FileMime: header.ContentTypeMp4Avc,
|
||||
FileMime: header.ContentTypeMp4AvcHigh,
|
||||
FileHash: "",
|
||||
},
|
||||
},
|
||||
|
||||
@@ -37,7 +37,7 @@ func ContentType(s string) string {
|
||||
return header.ContentTypeJpeg
|
||||
case "video/mp4; codecs=\"avc\"",
|
||||
"video/mp4; codecs=\"avc1\"":
|
||||
return header.ContentTypeMp4Avc // Advanced Video Coding (AVC), also known as H.264
|
||||
return header.ContentTypeMp4AvcHigh // Advanced Video Coding (AVC), also known as H.264
|
||||
case "video/mp4; codecs=\"hvc\"",
|
||||
"video/mp4; codecs=\"hvc1\"",
|
||||
"video/mp4; codecs=\"hevc\"":
|
||||
|
||||
@@ -30,6 +30,6 @@ func TestContent(t *testing.T) {
|
||||
assert.Equal(t, "image/png", ContentTypePng)
|
||||
assert.Equal(t, "image/jpeg", ContentTypeJpeg)
|
||||
assert.Equal(t, "image/svg+xml", ContentTypeSVG)
|
||||
assert.Equal(t, "video/mp4; codecs=\"avc1.640028\"", ContentTypeMp4Avc)
|
||||
assert.Equal(t, "video/mp4; codecs=\"avc1.640028\"", ContentTypeMp4AvcHigh)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -7,24 +7,36 @@ package header
|
||||
- https://ott.dolby.com/codec_test/index.html
|
||||
- https://dmnsgn.github.io/media-codecs/
|
||||
- https://cconcolato.github.io/media-mime-support/
|
||||
- https://cconcolato.github.io/media-mime-support/mediacapabilities.html
|
||||
- https://thorium.rocks/misc/h265-tester.html
|
||||
- https://developers.google.com/cast/docs/media
|
||||
- https://privacycheck.sec.lrz.de/active/fp_cpt/fp_can_play_type.html
|
||||
- https://chromium.googlesource.com/chromium/src.git/+/62.0.3178.1/content/browser/media/media_canplaytype_browsertest.cc
|
||||
*/
|
||||
|
||||
// Standard ContentType identifiers for audio and video files.
|
||||
const (
|
||||
ContentTypeMov = "video/quicktime"
|
||||
ContentTypeMp4 = "video/mp4"
|
||||
ContentTypeMp4Avc720 = ContentTypeMp4 + "; codecs=\"avc1.640020\"" // MPEG-4 AVC, High Profile Level 3.2
|
||||
ContentTypeMp4Avc = ContentTypeMp4 + "; codecs=\"avc1.640028\"" // MPEG-4 AVC, High Profile Level 4.0
|
||||
ContentTypeMp4Hevc = ContentTypeMp4 + "; codecs=\"hvc1.2.4.L120.B0\"" // HEVC Mp4 Main10 Profile, Main Tier, Level 4.0
|
||||
ContentTypeMp4Hev1 = ContentTypeMp4 + "; codecs=\"hev1.2.4.L120.B0\"" // HEVC Bitstream, not supported on macOS
|
||||
ContentTypeMp4AvcBaseline = ContentTypeMp4 + "; codecs=\"avc1.420028\"" // MPEG-4 AVC (H.264), Baseline Level 4.0
|
||||
ContentTypeMp4AvcMain = ContentTypeMp4 + "; codecs=\"avc1.4d0028\"" // MPEG-4 AVC (H.264), Main Level 4.0
|
||||
ContentTypeMp4AvcHigh = ContentTypeMp4 + "; codecs=\"avc1.640028\"" // MPEG-4 AVC (H.264), High Level 4.0
|
||||
ContentTypeMp4Avc3High = ContentTypeMp4 + "; codecs=\"avc3.640028\"" // MPEG-4 AVC Bitstream, High Profile, may not be supported on macOS
|
||||
ContentTypeMp4Hevc = ContentTypeMp4 + "; codecs=\"hvc1.1.6.L93.B0\"" // MPEG-4 HEVC (H.265), Main Profile
|
||||
ContentTypeMp4HevcHDR = ContentTypeMp4 + "; codecs=\"hev1.2.4.L153.B0\"" // MPEG-4 HEVC (H.265), Main 10 Profile
|
||||
ContentTypeMp4Hev1 = ContentTypeMp4 + "; codecs=\"hev1.1.6.L93.B0\"" // MPEG-4 HEVC Bitstream, Main Profile, not supported on macOS
|
||||
ContentTypeMp4Hev1HDR = ContentTypeMp4 + "; codecs=\"hev1.2.4.L153.B0\"" // MPEG-4 HEVC Bitstream, Main 10 Profile, not supported on macOS
|
||||
ContentTypeMp4Vvc = ContentTypeMp4 + "; codecs=\"vvc1\"" // Versatile Video Coding (VVC), also known as H.266
|
||||
ContentTypeMp4Evc = ContentTypeMp4 + "; codecs=\"evc1\"" // MPEG-5 Essential Video Coding (EVC), also known as ISO/IEC 23094-1
|
||||
ContentTypeTheora = "video/ogg"
|
||||
ContentTypeMov = "video/quicktime"
|
||||
ContentTypeMovAvcMain = ContentTypeMov + "; codecs=\"avc1.4d0028\"" // Apple QuickTime AVC, Main Level 4.0
|
||||
ContentTypeMovAvcHigh = ContentTypeMov + "; codecs=\"avc1.640028\"" // Apple QuickTime AVC, High Level 4.0
|
||||
ContentTypeOgg = "video/ogg"
|
||||
ContentTypeOggVorbis = ContentTypeOgg + "; codecs=\"vorbis\""
|
||||
ContentTypeOggTheora = ContentTypeOgg + "; codecs=\"theora, vorbis\""
|
||||
ContentTypeWebm = "video/webm"
|
||||
ContentTypeWebmVp8 = "video/webm; codecs=\"vp8\""
|
||||
ContentTypeWebmVp9 = "video/webm; codecs=\"vp09.00.10.08\""
|
||||
ContentTypeWebmAv1 = "video/webm; codecs=\"av01.2.10M.10\""
|
||||
ContentTypeWebmVp8 = ContentTypeWebm + "; codecs=\"vp8\""
|
||||
ContentTypeWebmVp9 = ContentTypeWebm + "; codecs=\"vp09.00.10.08\""
|
||||
ContentTypeWebmAv1 = ContentTypeWebm + "; codecs=\"av01.2.10M.10\""
|
||||
)
|
||||
|
||||
// Standard ContentType identifiers for images and vector graphics.
|
||||
|
||||
@@ -1,18 +1,15 @@
|
||||
package video
|
||||
|
||||
// Profile represents a video codec profile name,
|
||||
// see https://en.wikipedia.org/wiki/Advanced_Video_Coding#Profiles.
|
||||
type Profile = string
|
||||
|
||||
const (
|
||||
ProfileBaseline Profile = "BaseLine"
|
||||
ProfileMain Profile = "Main"
|
||||
ProfileHigh Profile = "High"
|
||||
)
|
||||
|
||||
// Profiles contains common video codec profiles together with their ContentType ID,
|
||||
// maximum bitrate, resolution, and frame rate (if known).
|
||||
var Profiles = CodecProfiles{
|
||||
// AvcProfiles contains common MPEG-4 AVC profiles together with their ContentType ID,
|
||||
// maximum bitrate, resolution, and frame rate (if known):
|
||||
// - https://dmnsgn.github.io/media-codecs/#AVC
|
||||
// - https://en.wikipedia.org/wiki/Advanced_Video_Coding#Profiles
|
||||
// - https://ott.dolby.com/codec_test/index.html
|
||||
// - https://cconcolato.github.io/media-mime-support/
|
||||
// - https://w3c.github.io/media-capabilities/
|
||||
// - https://privacycheck.sec.lrz.de/active/fp_cpt/fp_can_play_type.html
|
||||
// - https://chromium.googlesource.com/chromium/src.git/+/62.0.3178.1/content/browser/media/media_canplaytype_browsertest.cc
|
||||
var AvcProfiles = CodecProfiles{
|
||||
{Codec: CodecAvc, Profile: ProfileBaseline, Level: 30, Bitrate: 10000, ID: "avc1.66.30"}, // iOS friendly
|
||||
{Codec: CodecAvc, Profile: ProfileBaseline, Level: 30, Bitrate: 10000, ID: "avc1.42001e"},
|
||||
{Codec: CodecAvc, Profile: ProfileBaseline, Level: 31, Bitrate: 14000, ID: "avc1.42001f"},
|
||||
@@ -1,5 +1,17 @@
|
||||
package video
|
||||
|
||||
// Profile represents a video codec profile name,
|
||||
// see https://en.wikipedia.org/wiki/Advanced_Video_Coding#Profiles.
|
||||
type Profile = string
|
||||
|
||||
const (
|
||||
ProfileBaseline Profile = "Baseline"
|
||||
ProfileMain Profile = "Main"
|
||||
ProfileHigh Profile = "High"
|
||||
)
|
||||
|
||||
// CodecProfile represents a codec subtype with its standardized ID,
|
||||
// maximum bitrate, resolution, and frame rate (if known).
|
||||
type CodecProfile struct {
|
||||
Codec Codec
|
||||
Profile string
|
||||
@@ -11,4 +23,5 @@ type CodecProfile struct {
|
||||
ID string
|
||||
}
|
||||
|
||||
// CodecProfiles represents a set of codec subtypes.
|
||||
type CodecProfiles []CodecProfile
|
||||
|
||||
@@ -27,10 +27,12 @@ func ContentType(mediaType, fileType, videoCodec string) string {
|
||||
switch c {
|
||||
case "mov", "mp4":
|
||||
mediaType = header.ContentTypeMp4
|
||||
case CodecAvc, "avc":
|
||||
mediaType = header.ContentTypeMp4Avc // Advanced Video Coding (AVC), also known as H.264
|
||||
case CodecHevc, "hvc", "hevc":
|
||||
mediaType = header.ContentTypeMp4Hevc // High Efficiency Video Coding (HEVC), also known as H.265
|
||||
case CodecAvc3:
|
||||
mediaType = header.ContentTypeMp4Avc3High // AVC (H.264) Bitstream, High Profile
|
||||
case string(fs.VideoAvc), CodecAvc:
|
||||
mediaType = header.ContentTypeMp4AvcHigh // Advanced Video Coding (H.264), High Profile
|
||||
case string(fs.VideoHevc), CodecHevc, "hvc":
|
||||
mediaType = header.ContentTypeMp4Hevc // High Efficiency Video Coding (H.265)
|
||||
case CodecHev1, "hev":
|
||||
mediaType = header.ContentTypeMp4Hev1 // High Efficiency Video Coding (HEVC) Bitstream
|
||||
case CodecVvc, "vvc":
|
||||
@@ -44,7 +46,7 @@ func ContentType(mediaType, fileType, videoCodec string) string {
|
||||
case CodecAv1, "av1":
|
||||
mediaType = header.ContentTypeWebmAv1
|
||||
case CodecTheora, "ogg":
|
||||
mediaType = header.ContentTypeTheora
|
||||
mediaType = header.ContentTypeOggTheora
|
||||
case string(fs.VideoWebm):
|
||||
mediaType = header.ContentTypeWebm
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ func TestContentType(t *testing.T) {
|
||||
assert.Equal(t, fs.MimeTypeMp4, ContentType(fs.MimeTypeMp4, "", ""))
|
||||
})
|
||||
t.Run("Mp4_AVC", func(t *testing.T) {
|
||||
assert.Equal(t, header.ContentTypeMp4Avc, ContentType(fs.MimeTypeMp4, "", CodecAvc))
|
||||
assert.Equal(t, header.ContentTypeMp4AvcHigh, ContentType(fs.MimeTypeMp4, "", CodecAvc))
|
||||
})
|
||||
t.Run("Mp4_HVC", func(t *testing.T) {
|
||||
assert.Equal(t, header.ContentTypeMp4Hevc, ContentType(fs.MimeTypeMp4, "", CodecHevc))
|
||||
|
||||
@@ -28,7 +28,7 @@ func TestInfo(t *testing.T) {
|
||||
info := NewInfo()
|
||||
info.VideoMimeType = fs.MimeTypeMp4
|
||||
info.VideoCodec = CodecAvc
|
||||
assert.Equal(t, header.ContentTypeMp4Avc, info.VideoContentType())
|
||||
assert.Equal(t, header.ContentTypeMp4AvcHigh, info.VideoContentType())
|
||||
})
|
||||
t.Run("VideoFileExt", func(t *testing.T) {
|
||||
info := NewInfo()
|
||||
|
||||
@@ -40,7 +40,7 @@ func TestProbeFile(t *testing.T) {
|
||||
assert.Equal(t, media.Video, info.MediaType)
|
||||
assert.Equal(t, CodecAvc, info.VideoCodec)
|
||||
assert.Equal(t, fs.MimeTypeMp4, info.VideoMimeType)
|
||||
assert.Equal(t, header.ContentTypeMp4Avc, info.VideoContentType())
|
||||
assert.Equal(t, header.ContentTypeMp4AvcHigh, info.VideoContentType())
|
||||
assert.Equal(t, "810.0081ms", info.Duration.String())
|
||||
assert.InEpsilon(t, 0.81, info.Duration.Seconds(), 0.01)
|
||||
assert.Equal(t, 1, info.Tracks)
|
||||
@@ -67,7 +67,7 @@ func TestProbeFile(t *testing.T) {
|
||||
assert.Equal(t, media.Video, info.MediaType)
|
||||
assert.Equal(t, CodecAvc, info.VideoCodec)
|
||||
assert.Equal(t, fs.MimeTypeMp4, info.VideoMimeType)
|
||||
assert.Equal(t, header.ContentTypeMp4Avc, info.VideoContentType())
|
||||
assert.Equal(t, header.ContentTypeMp4AvcHigh, info.VideoContentType())
|
||||
assert.Equal(t, "1.066666666s", info.Duration.String())
|
||||
assert.InEpsilon(t, 1.066, info.Duration.Seconds(), 0.01)
|
||||
assert.Equal(t, 2, info.Tracks)
|
||||
@@ -147,7 +147,7 @@ func TestProbeFile(t *testing.T) {
|
||||
assert.Equal(t, media.Live, info.MediaType)
|
||||
assert.Equal(t, CodecAvc, info.VideoCodec)
|
||||
assert.Equal(t, fs.MimeTypeMp4, info.VideoMimeType)
|
||||
assert.Equal(t, header.ContentTypeMp4Avc, info.VideoContentType())
|
||||
assert.Equal(t, header.ContentTypeMp4AvcHigh, info.VideoContentType())
|
||||
assert.Equal(t, "1.024s", info.Duration.String())
|
||||
assert.InEpsilon(t, 1.024, info.Duration.Seconds(), 0.01)
|
||||
assert.Equal(t, 2, info.Tracks)
|
||||
@@ -180,7 +180,7 @@ func TestProbe(t *testing.T) {
|
||||
assert.Equal(t, media.Video, info.MediaType)
|
||||
assert.Equal(t, CodecAvc, info.VideoCodec)
|
||||
assert.Equal(t, fs.MimeTypeMp4, info.VideoMimeType)
|
||||
assert.Equal(t, header.ContentTypeMp4Avc, info.VideoContentType())
|
||||
assert.Equal(t, header.ContentTypeMp4AvcHigh, info.VideoContentType())
|
||||
assert.Equal(t, "810.0081ms", info.Duration.String())
|
||||
assert.InEpsilon(t, 0.81, info.Duration.Seconds(), 0.01)
|
||||
assert.Equal(t, 1, info.Tracks)
|
||||
@@ -210,7 +210,7 @@ func TestProbe(t *testing.T) {
|
||||
assert.Equal(t, media.Video, info.MediaType)
|
||||
assert.Equal(t, CodecAvc, info.VideoCodec)
|
||||
assert.Equal(t, fs.MimeTypeMp4, info.VideoMimeType)
|
||||
assert.Equal(t, header.ContentTypeMp4Avc, info.VideoContentType())
|
||||
assert.Equal(t, header.ContentTypeMp4AvcHigh, info.VideoContentType())
|
||||
assert.Equal(t, "1.024s", info.Duration.String())
|
||||
assert.InEpsilon(t, 1.024, info.Duration.Seconds(), 0.01)
|
||||
assert.Equal(t, 2, info.Tracks)
|
||||
@@ -240,7 +240,7 @@ func TestProbe(t *testing.T) {
|
||||
assert.Equal(t, media.Live, info.MediaType)
|
||||
assert.Equal(t, CodecAvc, info.VideoCodec)
|
||||
assert.Equal(t, fs.MimeTypeMp4, info.VideoMimeType)
|
||||
assert.Equal(t, header.ContentTypeMp4Avc, info.VideoContentType())
|
||||
assert.Equal(t, header.ContentTypeMp4AvcHigh, info.VideoContentType())
|
||||
assert.Equal(t, "1.024s", info.Duration.String())
|
||||
assert.InEpsilon(t, 1.024, info.Duration.Seconds(), 0.01)
|
||||
assert.Equal(t, 2, info.Tracks)
|
||||
|
||||
@@ -15,7 +15,7 @@ var Unknown = Type{
|
||||
var Mp4 = Type{
|
||||
Codec: CodecAvc,
|
||||
FileType: fs.VideoMp4,
|
||||
ContentType: header.ContentTypeMp4Avc,
|
||||
ContentType: header.ContentTypeMp4AvcHigh,
|
||||
WidthLimit: 8192,
|
||||
HeightLimit: 4320,
|
||||
Public: true,
|
||||
@@ -30,7 +30,8 @@ var Mov = Type{
|
||||
Public: true,
|
||||
}
|
||||
|
||||
// Avc specifies the MPEG-4 Advanced Video Coding (H.264) format.
|
||||
// Avc specifies the MPEG-4 Advanced Video Coding (H.264) format,
|
||||
// see https://en.wikipedia.org/wiki/Advanced_Video_Coding.
|
||||
var Avc = Type{
|
||||
Codec: CodecAvc,
|
||||
FileType: fs.VideoAvc,
|
||||
|
||||
Reference in New Issue
Block a user