Skip to content

Commit

Permalink
issue-212: add rotation info from metadata (#529)
Browse files Browse the repository at this point in the history
* issue-212: add rotation info from metadata

* fix typo: info -> infos

* assign rotation to VideoFileClip and write test for PR

* change assignment to equality statement.
  • Loading branch information
taddyhuo authored and bearney74 committed Apr 6, 2017
1 parent 2648a86 commit b76beb4
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 21 deletions.
37 changes: 19 additions & 18 deletions moviepy/video/io/VideoFileClip.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,27 +8,27 @@
class VideoFileClip(VideoClip):

"""
A video clip originating from a movie file. For instance: ::
>>> clip = VideoFileClip("myHolidays.mp4")
>>> clip2 = VideoFileClip("myMaskVideo.avi")
Parameters
------------
filename:
The name of the video file. It can have any extension supported
by ffmpeg: .ogv, .mp4, .mpeg, .avi, .mov etc.
has_mask:
Set this to 'True' if there is a mask included in the videofile.
Video files rarely contain masks, but some video codecs enable
that. For istance if you have a MoviePy VideoClip with a mask you
can save it to a videofile with a mask. (see also
can save it to a videofile with a mask. (see also
``VideoClip.write_videofile`` for more details).
audio:
Set to `False` if the clip doesn't have any audio or if you do not
wish to read the audio.
Expand All @@ -43,32 +43,32 @@ class VideoFileClip(VideoClip):
The algorithm used for resizing. Default: "bicubic", other popular
options include "bilinear" and "fast_bilinear". For more information, see
https://ffmpeg.org/ffmpeg-scaler.html
fps_source:
The fps value to collect from the metadata. Set by default to 'tbr', but
can be set to 'fps', which may be helpful if importing slow-motion videos
that get messed up otherwise.
Attributes
-----------
filename:
Name of the original video file.
fps:
Frames per second in the original file.
Read docstrings for Clip() and VideoClip() for other, more generic, attributes.
"""

def __init__(self, filename, has_mask=False,
audio=True, audio_buffersize = 200000,
target_resolution=None, resize_algorithm='bicubic',
audio_fps=44100, audio_nbytes=2, verbose=False,
fps_source='tbr'):

VideoClip.__init__(self)

# Make a reader
Expand All @@ -82,10 +82,11 @@ def __init__(self, filename, has_mask=False,
# Make some of the reader's attributes accessible from the clip
self.duration = self.reader.duration
self.end = self.reader.duration

self.fps = self.reader.fps
self.size = self.reader.size

self.rotation = self.reader.rotation

self.filename = self.reader.filename

if has_mask:
Expand All @@ -99,7 +100,7 @@ def __init__(self, filename, has_mask=False,
else:

self.make_frame = lambda t: self.reader.get_frame(t)

# Make a reader for the audio, if any.
if audio and self.reader.infos['audio_found']:

Expand Down
21 changes: 18 additions & 3 deletions moviepy/video/io/ffmpeg_reader.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ def __init__(self, filename, print_infos=False, bufsize = None,
fps_source)
self.fps = infos['video_fps']
self.size = infos['video_size']
self.rotation = infos['video_rotation']

if target_resolution:
# revert the order, as ffmpeg used (width, height)
Expand All @@ -40,7 +41,7 @@ def __init__(self, filename, print_infos=False, bufsize = None,
if None in target_resolution:
ratio = 1
for idx, target in enumerate(target_resolution):
if target:
if target:
ratio = target / self.size[idx]
self.size = (int(self.size[0] * ratio), int(self.size[1] * ratio))
else:
Expand Down Expand Up @@ -159,12 +160,12 @@ def get_frame(self, t):
"""

# these definitely need to be rechecked sometime. Seems to work.

# I use that horrible '+0.00001' hack because sometimes due to numerical
# imprecisions a 3.0 can become a 2.99999999... which makes the int()
# go to the previous integer. This makes the fetching more robust in the
# case where you get the nth frame by writing get_frame(n/fps).

pos = int(self.fps*t + 0.00001)+1

if pos == self.pos:
Expand Down Expand Up @@ -359,6 +360,20 @@ def get_fps():
# of frames, as follows:
# >>> result['video_duration'] = result['video_nframes'] / result['video_fps']

# get the video rotation info.
try:
rotation_lines = [l for l in lines if 'rotate :' in l and re.search('\d+$', l)]
if len(rotation_lines):
rotation_line = rotation_lines[0]
match = re.search('\d+$', rotation_line)
result['video_rotation'] = int(rotation_line[match.start() : match.end()])
else:
result['video_rotation'] = 0
except:
raise IOError(("MoviePy error: failed to read video rotation in file %s.\n"
"Here are the file infos returned by ffmpeg:\n\n%s")%(
filename, infos))


lines_audio = [l for l in lines if ' Audio: ' in l]

Expand Down
4 changes: 4 additions & 0 deletions tests/test_PR.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,5 +89,9 @@ def test_PR_515():
clip = VideoFileClip("media/fire2.mp4", fps_source='fps')
assert clip.fps == 10.51

def test_PR_529():
video_clip = VideoFileClip("media/fire2.mp4")
assert video_clip.rotation ==180

if __name__ == '__main__':
pytest.main()

0 comments on commit b76beb4

Please sign in to comment.