def _test_for_extension(self, extension: str, mock_datetime): from flamenco.job_compilers import blender_video_chunks, commands job_doc = JobDocForTesting({ '_id': ObjectId(24 * 'f'), '_created': self.created, 'settings': { 'frames': '100-250', 'fps': 24, 'chunk_size': 100, 'render_output': '/tmp/render/spring/export/FILENAME.MKV', 'filepath': '/spring/edit/sprloing.blend', 'output_file_extension': extension, 'images_or_video': 'video', 'extract_audio': True, }, 'job_type': 'blender-video-chunks', }) task_manager = mock.Mock() job_manager = mock.Mock() # Create a stable 'now' for testing. mock_datetime.now.side_effect = [self.mock_now, self.mock_now] # We expect: # - 1 move-out-of-way task # - 2 frame rendering chunks of resp. 100 and 51 frames each # - 2 video encoding chunks # - 1 concat-videos task # - 1 extract-audio task # - 1 encode-audio task (because extracting only works to FLAC at the moment) # - 1 mux-audio task # - 1 move-to-final task # so that's 10 tasks in total. task_ids = [ObjectId() for _ in range(10)] task_manager.api_create_task.side_effect = task_ids compiler = blender_video_chunks.BlenderVideoChunks( task_manager=task_manager, job_manager=job_manager) compiler.compile(job_doc) frames = '/tmp/render/spring/export/frames' expected_final_output = f'/tmp/render/spring/export/' \ f'{self.mock_now:%Y_%m_%d}-sprloing{extension}' task_manager.api_create_task.assert_has_calls([ mock.call( # 0 job_doc, [commands.MoveOutOfWay(src=frames)], 'move-out-of-way', status='under-construction', task_type='file-management', ), # Chunk (frames + video) tasks mock.call( # 1 job_doc, [commands.BlenderRender( blender_cmd='{blender}', filepath='/spring/edit/sprloing.blend', render_output=f'{frames}/chunk-00100-00199/######.png', format='PNG', frames='100..199')], 'frame-chunk-100-199', status='under-construction', task_type='blender-render', parents=[task_ids[0]], ), mock.call( # 2 job_doc, [commands.CreateVideo( ffmpeg_cmd='{ffmpeg}', input_files=f'{frames}/chunk-00100-00199/*.png', output_file=f'{frames}/chunk-00100-00199{extension}', fps=24)], 'video-chunk-100-199', status='under-construction', task_type='video-encoding', parents=[task_ids[1]], ), mock.call( # 3 job_doc, [commands.BlenderRender( blender_cmd='{blender}', filepath='/spring/edit/sprloing.blend', render_output=f'{frames}/chunk-00200-00250/######.png', format='PNG', frames='200..250')], 'frame-chunk-200-250', status='under-construction', task_type='blender-render', parents=[task_ids[0]], ), mock.call( # 4 job_doc, [commands.CreateVideo( ffmpeg_cmd='{ffmpeg}', input_files=f'{frames}/chunk-00200-00250/*.png', output_file=f'{frames}/chunk-00200-00250{extension}', fps=24)], 'video-chunk-200-250', status='under-construction', task_type='video-encoding', parents=[task_ids[3]], ), # Extract & encode the audio mock.call( # 5 job_doc, [commands.BlenderRenderAudio( blender_cmd='{blender}', filepath='/spring/edit/sprloing.blend', render_output=f'{frames}/audio.flac', frame_start=100, frame_end=250)], 'render-audio', status='under-construction', task_type='blender-render', parents=[task_ids[0]], ), mock.call( # 6 job_doc, [commands.EncodeAudio( ffmpeg_cmd='{ffmpeg}', input_file=f'{frames}/audio.flac', codec='aac', bitrate='192k', output_file=f'{frames}/audio.aac', )], 'encode-audio', status='under-construction', task_type='video-encoding', parents=[task_ids[5]], ), # Create a video of the chunks. mock.call( # 7 job_doc, [commands.ConcatenateVideos( ffmpeg_cmd='{ffmpeg}', input_files=f'{frames}/chunk-*{extension}', output_file=f'{frames}/video.mkv', )], 'concatenate-videos', status='under-construction', task_type='video-encoding', parents=[task_ids[2], task_ids[4]], ), # Mux the audio into the video. mock.call( # 8 job_doc, [commands.MuxAudio( ffmpeg_cmd='{ffmpeg}', audio_file=f'{frames}/audio.aac', video_file=f'{frames}/video.mkv', output_file=f'{frames}/muxed.mkv', )], 'mux-audio-video', status='under-construction', task_type='video-encoding', parents=[task_ids[6], task_ids[7]], ), # Move the file to its final place mock.call( # 9 job_doc, [commands.MoveWithCounter( src=f'{frames}/muxed.mkv', dest=expected_final_output, )], 'move-with-counter', status='under-construction', task_type='file-management', parents=[task_ids[8]], ), ]) task_manager.api_set_task_status_for_job.assert_called_with( job_doc['_id'], 'under-construction', 'queued', now=self.mock_now) job_manager.api_set_job_status(job_doc['_id'], 'under-construction', 'queued', now=self.mock_now)
def create_video_without_proper_task_type_support(self): from flamenco.job_compilers import blender_render, commands with self.app.app_context(): self.flamenco.db('managers').update_one( {'_id': self.mngr_id}, # No video-encoding task type {'$set': { 'worker_task_types': ['blender-render'] }}) job_doc = JobDocForTesting({ '_id': ObjectId(24 * 'f'), '_created': self.created, 'manager': self.mngr_id, 'settings': { 'frames': '1-5', 'chunk_size': 3, 'render_output': '/render/out/frames-######', 'format': 'OPEN_EXR', 'filepath': '/agent327/scenes/someshot/somefile.flamenco.blend', 'blender_cmd': '/path/to/blender --enable-new-depsgraph', # On top of pretty much the same settings as test_small_job(), # we add those settings that trigger the creation of the # create_video task. 'fps': 24, 'images_or_video': 'images', 'output_file_extension': '.exr', }, 'job_type': 'blender-render', }) task_manager = mock.Mock() job_manager = mock.Mock() # We expect: # - 2 chunk of 3 resp 2 frames. # - 1 create_video task. # - 1 move-to-final task. # so that's 4 tasks in total. task_ids = [ObjectId() for _ in range(4)] task_manager.api_create_task.side_effect = task_ids compiler = blender_render.BlenderRender(task_manager=task_manager, job_manager=job_manager) with self.app.app_context(): compiler.compile(job_doc) task_manager.api_create_task.assert_has_calls([ # Render tasks mock.call( job_doc, [ commands.BlenderRender( blender_cmd='/path/to/blender --enable-new-depsgraph', filepath= '/agent327/scenes/someshot/somefile.flamenco.blend', format='OPEN_EXR', render_output= '/render/out__intermediate-2018-07-06_115233/frames-######', frames='1..3') ], 'blender-render-1-3', status='under-construction', task_type='blender-render', parents=None, ), mock.call( job_doc, [ commands.BlenderRender( blender_cmd='/path/to/blender --enable-new-depsgraph', filepath= '/agent327/scenes/someshot/somefile.flamenco.blend', format='OPEN_EXR', render_output= '/render/out__intermediate-2018-07-06_115233/frames-######', frames='4,5') ], 'blender-render-4,5', status='under-construction', task_type='blender-render', parents=None, ), # Move to final location mock.call( job_doc, [ commands.MoveToFinal( src='/render/out__intermediate-2018-07-06_115233', dest='/render/out') ], 'move-to-final', parents=task_ids[1:2], status='under-construction', task_type='file-management', ), ]) task_manager.api_set_task_status_for_job.assert_called_with( job_doc['_id'], 'under-construction', 'queued', now=mock.ANY) job_manager.api_set_job_status(job_doc['_id'], 'under-construction', 'queued', now=mock.ANY)
def test_small_job(self, mock_datetime): from flamenco.job_compilers import blender_render, commands job_doc = JobDocForTesting({ '_id': ObjectId(24 * 'f'), '_created': self.created, 'settings': { 'frames': '1-5', 'chunk_size': 2, 'render_output': '/render/out/frames-######', 'format': 'EXR', 'filepath': '/agent327/scenes/someshot/somefile.blend', 'blender_cmd': '/path/to/blender --enable-new-depsgraph', }, 'job_type': 'blender-render', }) task_manager = mock.Mock() job_manager = mock.Mock() # Create a stable 'now' for testing. mock_now = datetime.datetime.now(tz=tz_util.utc) mock_datetime.now.side_effect = [mock_now] # We expect: # - 3 frame chunks of 2 frames each # - 1 move-to-final task # so that's 4 tasks in total. task_ids = [ObjectId() for _ in range(4)] task_manager.api_create_task.side_effect = task_ids compiler = blender_render.BlenderRender( task_manager=task_manager, job_manager=job_manager) compiler.compile(job_doc) task_manager.api_create_task.assert_has_calls([ # Render tasks mock.call( job_doc, [commands.BlenderRender( blender_cmd='/path/to/blender --enable-new-depsgraph', filepath='/agent327/scenes/someshot/somefile.blend', format='EXR', render_output='/render/out__intermediate-2018-07-06_115233/frames-######', frames='1,2')], 'blender-render-1,2', status='under-construction', task_type='blender-render', ), mock.call( job_doc, [commands.BlenderRender( blender_cmd='/path/to/blender --enable-new-depsgraph', filepath='/agent327/scenes/someshot/somefile.blend', format='EXR', render_output='/render/out__intermediate-2018-07-06_115233/frames-######', frames='3,4')], 'blender-render-3,4', status='under-construction', task_type='blender-render', ), mock.call( job_doc, [commands.BlenderRender( blender_cmd='/path/to/blender --enable-new-depsgraph', filepath='/agent327/scenes/someshot/somefile.blend', format='EXR', render_output='/render/out__intermediate-2018-07-06_115233/frames-######', frames='5')], 'blender-render-5', status='under-construction', task_type='blender-render', ), # Move to final location mock.call( job_doc, [commands.MoveToFinal( src='/render/out__intermediate-2018-07-06_115233', dest='/render/out')], 'move-to-final', parents=task_ids[0:3], status='under-construction', task_type='file-management', ), ]) task_manager.api_set_task_status_for_job.assert_called_with( job_doc['_id'], 'under-construction', 'queued', now=mock_now) job_manager.api_set_job_status(job_doc['_id'], 'under-construction', 'queued', now=mock_now)
def test_rna_overrides(self, mock_datetime): from flamenco.job_compilers import blender_render, commands job_doc = JobDocForTesting({ '_id': ObjectId(24 * 'f'), '_created': self.created, 'settings': { 'frames': '1-5', 'chunk_size': 2, 'render_output': '/render/out/frames-######', 'format': 'OPEN_EXR', 'filepath': '/agent327/scenes/someshot/somefile.blend', 'blender_cmd': '/path/to/blender --enable-new-depsgraph', 'rna_overrides': [ 'bpy.context.scene.render.stamp_note_text = "je moeder"', 'bpy.context.scene.render.use_stamp_note = True', 'bpy.context.scene.render.use_stamp = True', ], }, 'job_type': 'blender-render', }) expect_rna_overrides = '\n'.join([ blender_render.RNA_OVERRIDES_HEADER, *job_doc['settings']['rna_overrides'], '' ]) task_manager = mock.Mock() job_manager = mock.Mock() # Create a stable 'now' for testing. mock_now = datetime.datetime.now(tz=tz_util.utc) mock_datetime.now.side_effect = [mock_now] # We expect: # - 1 RNA override task # - 3 frame chunks of 2 frames each # - 1 move-to-final task # so that's 5 tasks in total. task_ids = [ObjectId() for _ in range(5)] task_manager.api_create_task.side_effect = task_ids compiler = blender_render.BlenderRender(task_manager=task_manager, job_manager=job_manager) compiler.compile(job_doc) task_manager.api_create_task.assert_has_calls([ # Override task mock.call( job_doc, [ commands.CreatePythonFile( filepath= '/agent327/scenes/someshot/somefile-overrides.py', contents=expect_rna_overrides, ) ], blender_render.RNA_OVERRIDES_TASK_NAME, status='under-construction', task_type='file-management', parents=None, ), # Render tasks mock.call( job_doc, [ commands.BlenderRender( blender_cmd='/path/to/blender --enable-new-depsgraph', filepath='/agent327/scenes/someshot/somefile.blend', format='OPEN_EXR', render_output= '/render/out__intermediate-2018-07-06_115233/frames-######', frames='1,2') ], 'blender-render-1,2', status='under-construction', task_type='blender-render', parents=[task_ids[0]], ), mock.call( job_doc, [ commands.BlenderRender( blender_cmd='/path/to/blender --enable-new-depsgraph', filepath='/agent327/scenes/someshot/somefile.blend', format='OPEN_EXR', render_output= '/render/out__intermediate-2018-07-06_115233/frames-######', frames='3,4') ], 'blender-render-3,4', status='under-construction', task_type='blender-render', parents=[task_ids[0]], ), mock.call( job_doc, [ commands.BlenderRender( blender_cmd='/path/to/blender --enable-new-depsgraph', filepath='/agent327/scenes/someshot/somefile.blend', format='OPEN_EXR', render_output= '/render/out__intermediate-2018-07-06_115233/frames-######', frames='5') ], 'blender-render-5', status='under-construction', task_type='blender-render', parents=[task_ids[0]], ), # Move to final location mock.call( job_doc, [ commands.MoveToFinal( src='/render/out__intermediate-2018-07-06_115233', dest='/render/out') ], 'move-to-final', parents=task_ids[1:4], status='under-construction', task_type='file-management', ), ]) task_manager.api_set_task_status_for_job.assert_called_with( job_doc['_id'], 'under-construction', 'queued', now=mock_now) job_manager.api_set_job_status(job_doc['_id'], 'under-construction', 'queued', now=mock_now)