9dc23c55bb495ef54ab7af7d3858fce27fb5303e
[mediagoblin.git] / mediagoblin / media_types / video / processing.py
1 # GNU MediaGoblin -- federated, autonomous media hosting
2 # Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS.
3 #
4 # This program is free software: you can redistribute it and/or modify
5 # it under the terms of the GNU Affero General Public License as published by
6 # the Free Software Foundation, either version 3 of the License, or
7 # (at your option) any later version.
8 #
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU Affero General Public License for more details.
13 #
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16
17 import tempfile
18 import logging
19 import os
20
21 from mediagoblin import mg_globals as mgg
22 from mediagoblin.processing import mark_entry_failed, \
23 THUMB_SIZE, MEDIUM_SIZE, create_pub_filepath
24 from . import transcoders
25
26 logging.basicConfig()
27
28 _log = logging.getLogger(__name__)
29 _log.setLevel(logging.DEBUG)
30
31
32 def process_video(entry):
33 """
34 Code to process a video
35
36 Much of this code is derived from the arista-transcoder script in
37 the arista PyPI package and changed to match the needs of
38 MediaGoblin
39
40 This function sets up the arista video encoder in some kind of new thread
41 and attaches callbacks to that child process, hopefully, the
42 entry-complete callback will be called when the video is done.
43 """
44 video_config = mgg.global_config['media_type:mediagoblin.media_types.video']
45
46 workbench = mgg.workbench_manager.create_workbench()
47
48 queued_filepath = entry.queued_media_file
49 queued_filename = workbench.localized_file(
50 mgg.queue_store, queued_filepath,
51 'source')
52
53 medium_filepath = create_pub_filepath(
54 entry,
55 '{original}-640p.webm'.format(
56 original=os.path.splitext(
57 queued_filepath[-1])[0] # Select the
58 ))
59
60 thumbnail_filepath = create_pub_filepath(
61 entry, 'thumbnail.jpg')
62
63
64 # Create a temporary file for the video destination
65 tmp_dst = tempfile.NamedTemporaryFile()
66
67 with tmp_dst:
68 # Transcode queued file to a VP8/vorbis file that fits in a 640x640 square
69 transcoder = transcoders.VideoTranscoder(queued_filename, tmp_dst.name)
70
71 # Push transcoded video to public storage
72 _log.debug('Saving medium...')
73 mgg.public_store.get_file(medium_filepath, 'wb').write(
74 tmp_dst.read())
75 _log.debug('Saved medium')
76
77 entry.media_files['webm_640'] = medium_filepath
78
79 # Save the width and height of the transcoded video
80 entry.media_data['video'] = {
81 u'width': transcoder.dst_data.videowidth,
82 u'height': transcoder.dst_data.videoheight}
83
84 # Create a temporary file for the video thumbnail
85 tmp_thumb = tempfile.NamedTemporaryFile()
86
87 with tmp_thumb:
88 # Create a thumbnail.jpg that fits in a 180x180 square
89 transcoders.VideoThumbnailer(queued_filename, tmp_thumb.name)
90
91 # Push the thumbnail to public storage
92 _log.debug('Saving thumbnail...')
93 mgg.public_store.get_file(thumbnail_filepath, 'wb').write(
94 tmp_thumb.read())
95 _log.debug('Saved thumbnail')
96
97 entry.media_files['thumb'] = thumbnail_filepath
98
99 if video_config['keep_original']:
100 # Push original file to public storage
101 queued_file = file(queued_filename, 'rb')
102
103 with queued_file:
104 original_filepath = create_pub_filepath(
105 entry,
106 queued_filepath[-1])
107
108 with mgg.public_store.get_file(original_filepath, 'wb') as \
109 original_file:
110 _log.debug('Saving original...')
111 original_file.write(queued_file.read())
112 _log.debug('Saved original')
113
114 entry.media_files['original'] = original_filepath
115
116 mgg.queue_store.delete_file(queued_filepath)
117
118 # Save the MediaEntry
119 entry.save()