Audio thumbnailing & spectrograms, media plugins use sniffing
[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 def sniff_handler(media_file, **kw):
32 transcoder = transcoders.VideoTranscoder()
33 try:
34 data = transcoder.discover(media_file.name)
35
36 _log.debug('Discovered: {0}'.format(data.__dict__))
37
38 if data.is_video == True:
39 return True
40 except:
41 _log.error('Exception caught when trying to discover {0}'.format(
42 kw.get('media')))
43
44 return False
45
46 def process_video(entry):
47 """
48 Process a video entry, transcode the queued media files (originals) and
49 create a thumbnail for the entry.
50 """
51 video_config = mgg.global_config['media_type:mediagoblin.media_types.video']
52
53 workbench = mgg.workbench_manager.create_workbench()
54
55 queued_filepath = entry.queued_media_file
56 queued_filename = workbench.localized_file(
57 mgg.queue_store, queued_filepath,
58 'source')
59
60 medium_filepath = create_pub_filepath(
61 entry,
62 '{original}-640p.webm'.format(
63 original=os.path.splitext(
64 queued_filepath[-1])[0] # Select the file name without .ext
65 ))
66
67 thumbnail_filepath = create_pub_filepath(
68 entry, 'thumbnail.jpg')
69
70
71 # Create a temporary file for the video destination
72 tmp_dst = tempfile.NamedTemporaryFile()
73
74 with tmp_dst:
75 # Transcode queued file to a VP8/vorbis file that fits in a 640x640 square
76 transcoder = transcoders.VideoTranscoder()
77 transcoder.transcode(queued_filename, tmp_dst.name)
78
79 # Push transcoded video to public storage
80 _log.debug('Saving medium...')
81 mgg.public_store.get_file(medium_filepath, 'wb').write(
82 tmp_dst.read())
83 _log.debug('Saved medium')
84
85 entry.media_files['webm_640'] = medium_filepath
86
87 # Save the width and height of the transcoded video
88 entry.media_data['video'] = {
89 u'width': transcoder.dst_data.videowidth,
90 u'height': transcoder.dst_data.videoheight}
91
92 # Create a temporary file for the video thumbnail
93 tmp_thumb = tempfile.NamedTemporaryFile()
94
95 with tmp_thumb:
96 # Create a thumbnail.jpg that fits in a 180x180 square
97 transcoders.VideoThumbnailer(queued_filename, tmp_thumb.name)
98
99 # Push the thumbnail to public storage
100 _log.debug('Saving thumbnail...')
101 mgg.public_store.get_file(thumbnail_filepath, 'wb').write(
102 tmp_thumb.read())
103 _log.debug('Saved thumbnail')
104
105 entry.media_files['thumb'] = thumbnail_filepath
106
107 if video_config['keep_original']:
108 # Push original file to public storage
109 queued_file = file(queued_filename, 'rb')
110
111 with queued_file:
112 original_filepath = create_pub_filepath(
113 entry,
114 queued_filepath[-1])
115
116 with mgg.public_store.get_file(original_filepath, 'wb') as \
117 original_file:
118 _log.debug('Saving original...')
119 original_file.write(queued_file.read())
120 _log.debug('Saved original')
121
122 entry.media_files['original'] = original_filepath
123
124 mgg.queue_store.delete_file(queued_filepath)
125
126 # Save the MediaEntry
127 entry.save()