ProcessingState: Document monkey patching.
[mediagoblin.git] / mediagoblin / media_types / video / processing.py
CommitLineData
93bdab9d 1# GNU MediaGoblin -- federated, autonomous media hosting
cf29e8a8 2# Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS.
93bdab9d
JW
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
25e39842 17from tempfile import NamedTemporaryFile
e9c1b938 18import logging
93bdab9d 19
93bdab9d 20from mediagoblin import mg_globals as mgg
45ab3e07 21from mediagoblin.decorators import get_workbench
196a5181 22from mediagoblin.processing import \
64712915 23 create_pub_filepath, FilenameBuilder, BaseProcessingFail, ProgressCallback
51eb0267
JW
24from mediagoblin.tools.translate import lazy_pass_to_ugettext as _
25
26729e02 26from . import transcoders
1f255101 27
8e5f9746
JW
28_log = logging.getLogger(__name__)
29_log.setLevel(logging.DEBUG)
93bdab9d
JW
30
31
51eb0267
JW
32class VideoTranscodingFail(BaseProcessingFail):
33 '''
34 Error raised if video transcoding fails
35 '''
36 general_message = _(u'Video transcoding failed')
37
38
ec4261a4 39def sniff_handler(media_file, **kw):
10085b77 40 transcoder = transcoders.VideoTranscoder()
4f4f2531 41 data = transcoder.discover(media_file.name)
10085b77 42
4f4f2531 43 _log.debug('Discovered: {0}'.format(data))
10085b77 44
4f4f2531
JW
45 if not data:
46 _log.error('Could not discover {0}'.format(
10085b77 47 kw.get('media')))
4f4f2531 48 return False
26729e02 49
4f4f2531
JW
50 if data['is_video'] == True:
51 return True
26729e02 52
ec4261a4 53 return False
93bdab9d 54
45ab3e07
SS
55@get_workbench
56def process_video(entry, workbench=None):
93bdab9d 57 """
5a34a80d
JW
58 Process a video entry, transcode the queued media files (originals) and
59 create a thumbnail for the entry.
45ab3e07
SS
60
61 A Workbench() represents a local tempory dir. It is automatically
62 cleaned up when this function exits.
93bdab9d 63 """
23caf305
CAW
64 video_config = mgg.global_config['media_type:mediagoblin.media_types.video']
65
8545cfc9 66 queued_filepath = entry.queued_media_file
93bdab9d
JW
67 queued_filename = workbench.localized_file(
68 mgg.queue_store, queued_filepath,
69 'source')
28f364bd 70 name_builder = FilenameBuilder(queued_filename)
93bdab9d 71
e9c1b938 72 medium_filepath = create_pub_filepath(
28f364bd 73 entry, name_builder.fill('{basename}-640p.webm'))
93bdab9d 74
e9c1b938 75 thumbnail_filepath = create_pub_filepath(
28f364bd 76 entry, name_builder.fill('{basename}.thumbnail.jpg'))
93bdab9d 77
c00e18fe
SS
78 # Create a temporary file for the video destination (cleaned up with workbench)
79 tmp_dst = NamedTemporaryFile(dir=workbench.dir, delete=False)
e9c1b938
JW
80 with tmp_dst:
81 # Transcode queued file to a VP8/vorbis file that fits in a 640x640 square
64712915 82 progress_callback = ProgressCallback(entry)
10085b77 83 transcoder = transcoders.VideoTranscoder()
196a5181
JW
84 transcoder.transcode(queued_filename, tmp_dst.name,
85 vp8_quality=video_config['vp8_quality'],
86 vp8_threads=video_config['vp8_threads'],
64712915
JW
87 vorbis_quality=video_config['vorbis_quality'],
88 progress_callback=progress_callback)
93bdab9d 89
c00e18fe
SS
90 # Push transcoded video to public storage
91 _log.debug('Saving medium...')
92 mgg.public_store.copy_local_to_storage(tmp_dst.name, medium_filepath)
93 _log.debug('Saved medium')
e9c1b938 94
c00e18fe 95 entry.media_files['webm_640'] = medium_filepath
e9c1b938 96
c00e18fe
SS
97 # Save the width and height of the transcoded video
98 entry.media_data_init(
99 width=transcoder.dst_data.videowidth,
100 height=transcoder.dst_data.videoheight)
93bdab9d 101
c00e18fe
SS
102 # Temporary file for the video thumbnail (cleaned up with workbench)
103 tmp_thumb = NamedTemporaryFile(dir=workbench.dir, suffix='.jpg', delete=False)
93bdab9d 104
e9c1b938
JW
105 with tmp_thumb:
106 # Create a thumbnail.jpg that fits in a 180x180 square
e4a1b6d2
JW
107 transcoders.VideoThumbnailerMarkII(
108 queued_filename,
109 tmp_thumb.name,
110 180)
1f255101 111
c00e18fe
SS
112 # Push the thumbnail to public storage
113 _log.debug('Saving thumbnail...')
114 mgg.public_store.copy_local_to_storage(tmp_thumb.name, thumbnail_filepath)
115 entry.media_files['thumb'] = thumbnail_filepath
93bdab9d 116
23caf305
CAW
117 if video_config['keep_original']:
118 # Push original file to public storage
c00e18fe
SS
119 _log.debug('Saving original...')
120 original_filepath = create_pub_filepath(entry, queued_filepath[-1])
121 mgg.public_store.copy_local_to_storage(queued_filename, original_filepath)
122 entry.media_files['original'] = original_filepath
93bdab9d 123
e9c1b938 124 mgg.queue_store.delete_file(queued_filepath)