def transcode(self, quality=None): if not quality: quality = self.audio_config['quality'] if self._skip_processing('webm_audio', quality=quality): return progress_callback = ProgressCallback(self.entry) webm_audio_tmp = os.path.join( self.workbench.dir, self.name_builder.fill('{basename}{ext}')) self.transcoder.transcode(self.process_filename, webm_audio_tmp, quality=quality, progress_callback=progress_callback) self.transcoder.discover(webm_audio_tmp) self._keep_best() _log.debug('Saving medium...') store_public(self.entry, 'webm_audio', webm_audio_tmp, self.name_builder.fill('{basename}.medium.webm')) self.entry.set_file_metadata('webm_audio', **{'quality': quality})
def transcode(self, medium_size=None, vp8_quality=None, vp8_threads=None, vorbis_quality=None): progress_callback = ProgressCallback(self.entry) tmp_dst = os.path.join(self.workbench.dir, self.name_builder.fill('{basename}.medium.webm')) if not medium_size: medium_size = ( mgg.global_config['media:medium']['max_width'], mgg.global_config['media:medium']['max_height']) if not vp8_quality: vp8_quality = self.video_config['vp8_quality'] if not vp8_threads: vp8_threads = self.video_config['vp8_threads'] if not vorbis_quality: vorbis_quality = self.video_config['vorbis_quality'] file_metadata = {'medium_size': medium_size, 'vp8_threads': vp8_threads, 'vp8_quality': vp8_quality, 'vorbis_quality': vorbis_quality} if self._skip_processing('webm_video', **file_metadata): return # Extract metadata and keep a record of it metadata = self.transcoder.discover(self.process_filename) store_metadata(self.entry, metadata) # Figure out whether or not we need to transcode this video or # if we can skip it if skip_transcode(metadata, medium_size): _log.debug('Skipping transcoding') dst_dimensions = metadata['videowidth'], metadata['videoheight'] # If there is an original and transcoded, delete the transcoded # since it must be of lower quality then the original if self.entry.media_files.get('original') and \ self.entry.media_files.get('webm_video'): self.entry.media_files['webm_video'].delete() else: self.transcoder.transcode(self.process_filename, tmp_dst, vp8_quality=vp8_quality, vp8_threads=vp8_threads, vorbis_quality=vorbis_quality, progress_callback=progress_callback, dimensions=tuple(medium_size)) dst_dimensions = self.transcoder.dst_data.videowidth,\ self.transcoder.dst_data.videoheight self._keep_best() # Push transcoded video to public storage _log.debug('Saving medium...') store_public(self.entry, 'webm_video', tmp_dst, self.name_builder.fill('{basename}.medium.webm')) _log.debug('Saved medium') self.entry.set_file_metadata('webm_video', **file_metadata) self.did_transcode = True # Save the width and height of the transcoded video self.entry.media_data_init( width=dst_dimensions[0], height=dst_dimensions[1])
def transcode(self, medium_size=None, vp8_quality=None, vp8_threads=None, vorbis_quality=None): progress_callback = ProgressCallback(self.entry) tmp_dst = os.path.join(self.workbench.dir, self.part_filename) if not medium_size: medium_size = ( mgg.global_config['media:medium']['max_width'], mgg.global_config['media:medium']['max_height']) if not vp8_quality: vp8_quality = self.video_config['vp8_quality'] if not vp8_threads: vp8_threads = self.video_config['vp8_threads'] if not vorbis_quality: vorbis_quality = self.video_config['vorbis_quality'] file_metadata = {'medium_size': medium_size, 'vp8_threads': vp8_threads, 'vp8_quality': vp8_quality, 'vorbis_quality': vorbis_quality} if self._skip_processing(self.curr_file, **file_metadata): return metadata = transcoders.discover(self.process_filename) orig_dst_dimensions = (metadata.get_video_streams()[0].get_width(), metadata.get_video_streams()[0].get_height()) # Figure out whether or not we need to transcode this video or # if we can skip it if skip_transcode(metadata, medium_size): _log.debug('Skipping transcoding') # If there is an original and transcoded, delete the transcoded # since it must be of lower quality then the original if self.entry.media_files.get('original') and \ self.entry.media_files.get(self.curr_file): self.entry.media_files[self.curr_file].delete() else: _log.debug('Entered transcoder') video_config = (mgg.global_config['plugins'] ['mediagoblin.media_types.video']) num_res = len(video_config['available_resolutions']) default_res = video_config['default_resolution'] self.transcoder.transcode(self.process_filename, tmp_dst, default_res, num_res, vp8_quality=vp8_quality, vp8_threads=vp8_threads, vorbis_quality=vorbis_quality, progress_callback=progress_callback, dimensions=tuple(medium_size)) if self.transcoder.dst_data: # Push transcoded video to public storage _log.debug('Saving medium...') store_public(self.entry, self.curr_file, tmp_dst, self.part_filename) _log.debug('Saved medium') self.entry.set_file_metadata(self.curr_file, **file_metadata) self.did_transcode = True
def process_video(proc_state): """ Process a video entry, transcode the queued media files (originals) and create a thumbnail for the entry. A Workbench() represents a local tempory dir. It is automatically cleaned up when this function exits. """ entry = proc_state.entry workbench = proc_state.workbench video_config = mgg.global_config['media_type:mediagoblin.media_types.video'] queued_filepath = entry.queued_media_file queued_filename = proc_state.get_queued_filename() name_builder = FilenameBuilder(queued_filename) medium_basename = name_builder.fill('{basename}-640p.webm') medium_filepath = create_pub_filepath(entry, medium_basename) thumbnail_basename = name_builder.fill('{basename}.thumbnail.jpg') thumbnail_filepath = create_pub_filepath(entry, thumbnail_basename) # Create a temporary file for the video destination (cleaned up with workbench) tmp_dst = os.path.join(workbench.dir, medium_basename) # Transcode queued file to a VP8/vorbis file that fits in a 640x640 square progress_callback = ProgressCallback(entry) dimensions = ( mgg.global_config['media:medium']['max_width'], mgg.global_config['media:medium']['max_height']) # Extract metadata and keep a record of it metadata = transcoders.VideoTranscoder().discover(queued_filename) store_metadata(entry, metadata) # Figure out whether or not we need to transcode this video or # if we can skip it if skip_transcode(metadata): _log.debug('Skipping transcoding') dst_dimensions = metadata['videowidth'], metadata['videoheight'] # Push original file to public storage _log.debug('Saving original...') proc_state.copy_original(queued_filepath[-1]) did_transcode = False else: transcoder = transcoders.VideoTranscoder() transcoder.transcode(queued_filename, tmp_dst, vp8_quality=video_config['vp8_quality'], vp8_threads=video_config['vp8_threads'], vorbis_quality=video_config['vorbis_quality'], progress_callback=progress_callback, dimensions=dimensions) dst_dimensions = transcoder.dst_data.videowidth,\ transcoder.dst_data.videoheight # Push transcoded video to public storage _log.debug('Saving medium...') mgg.public_store.copy_local_to_storage(tmp_dst, medium_filepath) _log.debug('Saved medium') entry.media_files['webm_640'] = medium_filepath did_transcode = True # Save the width and height of the transcoded video entry.media_data_init( width=dst_dimensions[0], height=dst_dimensions[1]) # Temporary file for the video thumbnail (cleaned up with workbench) tmp_thumb = os.path.join(workbench.dir, thumbnail_basename) # Create a thumbnail.jpg that fits in a 180x180 square transcoders.VideoThumbnailerMarkII( queued_filename, tmp_thumb, 180) # Push the thumbnail to public storage _log.debug('Saving thumbnail...') mgg.public_store.copy_local_to_storage(tmp_thumb, thumbnail_filepath) entry.media_files['thumb'] = thumbnail_filepath # save the original... but only if we did a transcoding # (if we skipped transcoding and just kept the original anyway as the main # media, then why would we save the original twice?) if video_config['keep_original'] and did_transcode: # Push original file to public storage _log.debug('Saving original...') proc_state.copy_original(queued_filepath[-1]) # Remove queued media file from storage and database proc_state.delete_queue_file()
def process_audio(proc_state): """Code to process uploaded audio. Will be run by celery. A Workbench() represents a local tempory dir. It is automatically cleaned up when this function exits. """ entry = proc_state.entry workbench = proc_state.workbench audio_config = mgg.global_config[ 'media_type:mediagoblin.media_types.audio'] queued_filepath = entry.queued_media_file queued_filename = workbench.localized_file(mgg.queue_store, queued_filepath, 'source') name_builder = FilenameBuilder(queued_filename) webm_audio_filepath = create_pub_filepath( entry, '{original}.webm'.format( original=os.path.splitext(queued_filepath[-1])[0])) if audio_config['keep_original']: with open(queued_filename, 'rb') as queued_file: original_filepath = create_pub_filepath( entry, name_builder.fill('{basename}{ext}')) with mgg.public_store.get_file(original_filepath, 'wb') as \ original_file: _log.debug('Saving original...') original_file.write(queued_file.read()) entry.media_files['original'] = original_filepath transcoder = AudioTranscoder() with NamedTemporaryFile(dir=workbench.dir) as webm_audio_tmp: progress_callback = ProgressCallback(entry) transcoder.transcode(queued_filename, webm_audio_tmp.name, quality=audio_config['quality'], progress_callback=progress_callback) transcoder.discover(webm_audio_tmp.name) _log.debug('Saving medium...') mgg.public_store.get_file(webm_audio_filepath, 'wb').write(webm_audio_tmp.read()) entry.media_files['webm_audio'] = webm_audio_filepath # entry.media_data_init(length=int(data.audiolength)) if audio_config['create_spectrogram']: spectrogram_filepath = create_pub_filepath( entry, '{original}-spectrogram.jpg'.format( original=os.path.splitext(queued_filepath[-1])[0])) with NamedTemporaryFile(dir=workbench.dir, suffix='.ogg') as wav_tmp: _log.info('Creating OGG source for spectrogram') transcoder.transcode( queued_filename, wav_tmp.name, mux_string='vorbisenc quality={0} ! oggmux'.format( audio_config['quality'])) thumbnailer = AudioThumbnailer() with NamedTemporaryFile(dir=workbench.dir, suffix='.jpg') as spectrogram_tmp: thumbnailer.spectrogram( wav_tmp.name, spectrogram_tmp.name, width=mgg.global_config['media:medium']['max_width'], fft_size=audio_config['spectrogram_fft_size']) _log.debug('Saving spectrogram...') mgg.public_store.get_file(spectrogram_filepath, 'wb').write(spectrogram_tmp.read()) entry.media_files['spectrogram'] = spectrogram_filepath with NamedTemporaryFile(dir=workbench.dir, suffix='.jpg') as thumb_tmp: thumbnailer.thumbnail_spectrogram( spectrogram_tmp.name, thumb_tmp.name, (mgg.global_config['media:thumb']['max_width'], mgg.global_config['media:thumb']['max_height'])) thumb_filepath = create_pub_filepath( entry, '{original}-thumbnail.jpg'.format( original=os.path.splitext(queued_filepath[-1])[0])) mgg.public_store.get_file(thumb_filepath, 'wb').write(thumb_tmp.read()) entry.media_files['thumb'] = thumb_filepath else: entry.media_files['thumb'] = ['fake', 'thumb', 'path.jpg'] # Remove queued media file from storage and database. # queued_filepath is in the task_id directory which should # be removed too, but fail if the directory is not empty to be on # the super-safe side. mgg.queue_store.delete_file(queued_filepath) # rm file mgg.queue_store.delete_dir(queued_filepath[:-1]) # rm dir entry.queued_media_file = []