summaryrefslogtreecommitdiff
path: root/internal/media/ffmpeg.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/media/ffmpeg.go')
-rw-r--r--internal/media/ffmpeg.go101
1 files changed, 81 insertions, 20 deletions
diff --git a/internal/media/ffmpeg.go b/internal/media/ffmpeg.go
index 58c2f9503..693b6f490 100644
--- a/internal/media/ffmpeg.go
+++ b/internal/media/ffmpeg.go
@@ -224,8 +224,11 @@ func ffprobe(ctx context.Context, filepath string) (*result, error) {
// Show specifically stream codec names, types, frame rate, duration, dimens, and pixel format.
"stream=codec_name,codec_type,r_frame_rate,duration_ts,width,height,pix_fmt" + ":" +
- // Show orientation.
- "tags=orientation",
+ // Show orientation tag.
+ "tags=orientation" + ":" +
+
+ // Show rotation data.
+ "side_data=rotation",
// Limit to reading the first
// 1s of data looking for "rotation"
@@ -490,7 +493,7 @@ func (res *ffprobeResult) Process() (*result, error) {
}
// Check extra packet / frame information
- // for provided orientation (not always set).
+ // for provided orientation (if provided).
for _, pf := range res.PacketsAndFrames {
// Ensure frame contains tags.
@@ -498,23 +501,24 @@ func (res *ffprobeResult) Process() (*result, error) {
continue
}
- // Ensure orientation not
- // already been specified.
- if r.orientation != 0 {
- return nil, errors.New("multiple sets of orientation data")
- }
-
// Trim any space from orientation value.
str := strings.TrimSpace(pf.Tags.Orientation)
// Parse as integer value.
- i, _ := strconv.Atoi(str)
- if i < 0 || i >= 9 {
+ orient, _ := strconv.Atoi(str)
+ if orient < 0 || orient >= 9 {
return nil, errors.New("invalid orientation data")
}
- // Set orientation.
- r.orientation = i
+ // Ensure different value has
+ // not already been specified.
+ if r.orientation != 0 &&
+ orient != r.orientation {
+ return nil, errors.New("multiple sets of orientation / rotation data")
+ }
+
+ // Set new orientation.
+ r.orientation = orient
}
// Preallocate streams to max possible lengths.
@@ -554,6 +558,57 @@ func (res *ffprobeResult) Process() (*result, error) {
framerate = float32(num / den)
}
+ // Check for embedded sidedata
+ // which may contain rotation data.
+ for _, d := range s.SideDataList {
+
+ // Ensure frame side
+ // data IS rotation data.
+ if d.Rotation == 0 {
+ continue
+ }
+
+ // Drop any decimal
+ // rotation value.
+ rot := int(d.Rotation)
+
+ // Round rotation to multiple of 90.
+ // More granularity is not needed.
+ if q := rot % 90; q > 45 {
+ rot += (90 - q)
+ } else {
+ rot -= q
+ }
+
+ // Drop any value above 360
+ // or below -360, these are
+ // just repeat full turns.
+ //
+ // Then convert to
+ // orientation value.
+ var orient int
+ switch rot % 360 {
+ case 0:
+ orient = orientationNormal
+ case 90, -270:
+ orient = orientationRotate90
+ case 180:
+ orient = orientationRotate180
+ case 270, -90:
+ orient = orientationRotate270
+ }
+
+ // Ensure different value has
+ // not already been specified.
+ if r.orientation != 0 &&
+ orient != r.orientation {
+ return nil, errors.New("multiple sets of orientation / rotation data")
+ }
+
+ // Set new orientation.
+ r.orientation = orient
+ }
+
// Append video stream data to result.
r.video = append(r.video, videoStream{
stream: stream{codec: s.CodecName},
@@ -580,6 +635,7 @@ type ffprobeResult struct {
type ffprobePacketOrFrame struct {
Type string `json:"type"`
Tags ffprobeTags `json:"tags"`
+ // SideDataList []ffprobeSideData `json:"side_data_list"`
}
type ffprobeTags struct {
@@ -587,13 +643,18 @@ type ffprobeTags struct {
}
type ffprobeStream struct {
- CodecName string `json:"codec_name"`
- CodecType string `json:"codec_type"`
- PixFmt string `json:"pix_fmt"`
- RFrameRate string `json:"r_frame_rate"`
- DurationTS uint `json:"duration_ts"`
- Width int `json:"width"`
- Height int `json:"height"`
+ CodecName string `json:"codec_name"`
+ CodecType string `json:"codec_type"`
+ PixFmt string `json:"pix_fmt"`
+ RFrameRate string `json:"r_frame_rate"`
+ DurationTS uint `json:"duration_ts"`
+ Width int `json:"width"`
+ Height int `json:"height"`
+ SideDataList []ffprobeSideData `json:"side_data_list"`
+}
+
+type ffprobeSideData struct {
+ Rotation float64 `json:"rotation"`
}
type ffprobeFormat struct {