4 * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
30 #include "cwindowgui.h"
34 #include "edlsession.h"
37 #include "filesystem.h"
38 #include "indexfile.h"
41 #include "mwindowgui.h"
42 #include "packagerenderer.h"
43 #include "playabletracks.h"
44 #include "playbackconfig.h"
45 #include "pluginserver.h"
46 #include "preferences.h"
48 #include "renderengine.h"
49 #include "renderfarmfsserver.h"
51 #include "sighandler.h"
53 #include "transportque.h"
56 #include "videodevice.h"
65 RenderPackage::RenderPackage()
78 RenderPackage::~RenderPackage()
83 PackageFile::PackageFile(PackageRenderer *package_renderer)
85 this->package_renderer = package_renderer;
88 PackageFile::~PackageFile()
92 int PackageFile::write_frame_done(int64_t position)
94 if( !package_renderer->package->use_brender ) return 0;
95 return package_renderer->set_video_map(position, BRender::RENDERED);
99 // Used by RenderFarm and in the future, Render, to do packages.
100 PackageRenderer::PackageRenderer()
108 frames_per_second = 0;
111 PackageRenderer::~PackageRenderer()
115 audio_cache->remove_user();
117 video_cache->remove_user();
123 // PackageRenderer::initialize happens only once for every node when doing rendering session
124 // This is not called for each package!
126 int PackageRenderer::initialize(MWindow *mwindow,
128 Preferences *preferences,
129 Asset *default_asset)
133 this->mwindow = mwindow;
135 this->preferences = preferences;
136 this->default_asset = default_asset;
139 //printf("PackageRenderer::initialize %d\n", preferences->processors);
140 command = new TransportCommand(preferences);
141 command->command = NORMAL_FWD;
142 command->get_edl()->copy_all(edl);
143 command->change_type = CHANGE_ALL;
144 command->set_playback_range();
146 default_asset->frame_rate = command->get_edl()->session->frame_rate;
147 default_asset->sample_rate = command->get_edl()->session->sample_rate;
148 default_asset->aspect_ratio = (double)command->get_edl()->session->aspect_w /
149 command->get_edl()->session->aspect_h;
150 result = Render::check_asset(edl, *default_asset);
152 audio_cache = new CICache(preferences);
153 video_cache = new CICache(preferences);
155 //PlaybackConfig *config = command->get_edl()->session->playback_config;
156 aconfig = new AudioOutConfig();
157 vconfig = new VideoOutConfig;
162 void PackageRenderer::create_output()
165 asset = new Asset(*default_asset);
167 if( !get_master() && preferences->renderfarm_vfs && preferences->use_renderfarm )
168 snprintf(asset->path, sizeof(asset->path),
169 RENDERFARM_FS_PREFIX "%s", package->path);
171 strncpy(asset->path, package->path, sizeof(asset->path));
173 file = new PackageFile(this);
174 file->set_processors(preferences->processors);
175 result = file->open_file(preferences, asset, 0, 1);
177 if( result && mwindow ) {
179 char string[BCTEXTLEN];
180 snprintf(string, sizeof(string), _("Couldn't open %s"), asset->path);
181 ErrorBox error(_(PROGRAM_NAME ": Error"),
182 mwindow->gui->get_abs_cursor_x(1),
183 mwindow->gui->get_abs_cursor_y(1));
184 error.create_objects(string);
189 mwindow->sighandler->push_file(file);
190 IndexFile::delete_index(preferences, asset);
192 //printf("PackageRenderer::create_output %d %d\n", __LINE__, result);
195 void PackageRenderer::create_engine()
197 // Fix audio buffers to 1 second
198 audio_read_length = command->get_edl()->session->sample_rate;
199 command->get_edl()->session->playback_config->aconfig->fragment_size = audio_read_length;
201 aconfig->fragment_size = audio_read_length;
204 render_engine = new RenderEngine(0, preferences, 0, 0);
205 render_engine->set_acache(audio_cache);
206 render_engine->set_vcache(video_cache);
207 render_engine->arm_command(command);
209 if( package->use_brender ) {
210 audio_preroll = Units::to_int64((double)preferences->brender_preroll /
211 default_asset->frame_rate *
212 default_asset->sample_rate);
213 video_preroll = preferences->brender_preroll;
216 audio_preroll = Units::to_int64(preferences->render_preroll *
217 default_asset->sample_rate);
218 video_preroll = Units::to_int64(preferences->render_preroll *
219 default_asset->frame_rate);
221 audio_position = package->audio_start - audio_preroll;
222 if( audio_position < 0 ) {
223 audio_preroll += audio_position;
226 video_position = package->video_start - video_preroll;
227 if( video_position < 0 ) {
228 video_preroll += video_position;
235 // Create output buffers
236 if( asset->audio_data ) {
237 file->start_audio_thread(audio_read_length,
238 preferences->processors > 1 ? 2 : 1);
243 if( asset->video_data ) {
244 compressed_output = new VFrame;
245 // The write length needs to correlate with the processor count because
246 // it is passed to the file handler which usually processes frames simultaneously.
247 video_write_length = preferences->processors;
248 video_write_position = 0;
249 direct_frame_copying = 0;
252 //printf("PackageRenderer::create_engine %d video_write_length=%d\n", __LINE__, video_write_length);
253 // starting frames are corrupted if video_write_length > 2. Work around it, for now.
254 if( video_write_length > 2 ) {
255 video_write_length = 2;
257 file->start_video_thread(video_write_length,
258 command->get_edl()->session->color_model,
259 preferences->processors > 1 ? 2 : 1,
261 //printf("PackageRenderer::create_engine %d\n", __LINE__);
265 video_device = new VideoDevice;
266 video_device->open_output(vconfig,
267 command->get_edl()->session->frame_rate,
268 command->get_edl()->session->output_w,
269 command->get_edl()->session->output_h,
270 mwindow->cwindow->gui->canvas,
272 // video_device->start_playback();
277 playable_tracks = new PlayableTracks(render_engine->get_edl(),
288 void PackageRenderer::do_audio()
290 //printf("PackageRenderer::do_audio %d\n", __LINE__);
292 if( asset->audio_data ) {
293 audio_output = file->get_audio_buffer();
294 // Zero unused channels in output vector
295 for( int i = 0; i < MAX_CHANNELS; i++ ) {
296 audio_output_ptr[i] = (i < asset->channels) ?
303 // Call render engine
305 result = render_engine->arender->process_buffer(audio_output_ptr,
311 // Fix buffers for preroll
312 int64_t output_length = audio_read_length;
313 if( audio_preroll > 0 ) {
314 if( audio_preroll >= output_length )
317 output_length -= audio_preroll;
318 for( int i = 0; i < MAX_CHANNELS; i++ ) {
319 if( audio_output_ptr[i] ) {
320 double *data = audio_output_ptr[i]->get_data();
321 for( int j = 0; j < output_length; j++ ) {
322 data[j] = data[j + audio_read_length - output_length];
327 //printf("PackageRenderer::do_audio 4\n");
329 audio_preroll -= audio_read_length;
332 // Must perform writes even if 0 length so get_audio_buffer doesn't block
333 result |= file->write_audio_buffer(output_length);
336 audio_position += audio_read_length;
337 //printf("PackageRenderer::do_audio %d\n", __LINE__);
341 void PackageRenderer::do_video()
344 if( asset->video_data ) {
345 // get the absolute video position from the audio position
346 int64_t video_end = video_position + video_read_length;
348 if( video_end > package->video_end )
349 video_end = package->video_end;
351 while( !result && video_position < video_end ) {
352 // Try to copy the compressed frame directly from the input to output files
353 if( direct_frame_copy(command->get_edl(),
354 video_position, file, result) ) {
355 // Direct frame copy failed.
356 // Switch back to background compression
357 if( direct_frame_copying ) {
359 file->start_video_thread(video_write_length,
360 command->get_edl()->session->color_model,
361 preferences->processors > 1 ? 2 : 1,
363 //printf("PackageRenderer::do_video %d %d\n", __LINE__, preferences->processors);
364 direct_frame_copying = 0;
367 // Try to use the rendering engine to write the frame.
368 // Get a buffer for background writing.
370 if( video_write_position == 0 )
371 video_output = file->get_video_buffer();
372 // Construct layered output buffer
373 video_output_ptr = video_output[0][video_write_position];
376 result = render_engine->vrender->process_buffer(
377 video_output_ptr, video_position, 0);
380 video_device->output_visible() ) {
381 // Vector for video device
382 VFrame *preview_output;
384 video_device->new_output_buffer(&preview_output,
385 command->get_edl()->session->color_model,
388 preview_output->copy_from(video_output_ptr);
389 video_device->write_buffer(preview_output,
392 // Don't write to file
393 if( video_preroll && !result ) {
395 // Keep the write position at 0 until ready to write real frames
396 result = file->write_video_buffer(0);
397 video_write_position = 0;
401 // Set background rendering parameters
402 // Allow us to skip sections of the output file by setting the frame number.
403 // Used by background render and render farm.
404 video_output_ptr->set_number(video_position);
405 video_write_position++;
407 if( video_write_position >= video_write_length ) {
408 result = file->write_video_buffer(video_write_position);
409 video_write_position = 0;
415 if( !result && get_result() ) result = 1;
416 if( !result && progress_cancelled() ) result = 1;
420 video_position += video_read_length;
425 void PackageRenderer::stop_engine()
427 delete render_engine;
428 delete playable_tracks;
432 void PackageRenderer::stop_output()
435 if( asset->audio_data ) {
437 file->stop_audio_thread();
440 if( asset->video_data ) {
441 delete compressed_output;
442 if( video_write_position )
443 file->write_video_buffer(video_write_position);
444 video_write_position = 0;
445 if( !error ) file->stop_video_thread();
447 // video_device->stop_playback();
448 video_device->close_all();
455 void PackageRenderer::close_output()
458 mwindow->sighandler->pull_file(file);
461 asset->Garbage::remove_user();
464 // Aborts and returns 1 if an error is encountered.
465 int PackageRenderer::render_package(RenderPackage *package)
469 int samples_rendered = 0;
474 this->package = package;
477 // "PackageRenderer::render_package: audio s=%jd l=%jd video s=%jd l=%jd\n",
478 // package->audio_start,
479 // package->audio_end - package->audio_start,
480 // package->video_start,
481 // package->video_end - package->video_start);
483 if( debug ) PRINT_TRACE
485 if( package->video_do ) default_asset->video_data = 1;
486 if( package->audio_do ) default_asset->audio_data = 1;
487 Render::check_asset(edl, *default_asset);
489 // FIXME: The design that we only get EDL once does not give us neccessary flexiblity to do things the way they should be donek
490 default_asset->video_data = package->video_do;
491 default_asset->audio_data = package->audio_do;
492 Render::check_asset(edl, *default_asset);
496 if( !asset->video_data ) video_done = 1;
497 if( !asset->audio_data ) audio_done = 1;
499 // Create render engine
504 total_samples_rendered = 0;
505 while( !result && (!audio_done || !video_done) ) {
506 int need_audio = 0, need_video = 0;
507 // Calculate lengths to process. Audio fragment is constant.
509 if( audio_position + audio_read_length >= package->audio_end ) {
511 audio_read_length = package->audio_end - audio_position;
514 samples_rendered = audio_read_length;
518 //printf("PackageRenderer::render_package 6 %d\n", samples_rendered);
522 // video_read_length = package->video_end - video_position;
523 // // Packetize video length so progress gets updated
524 // video_read_length = (int)MIN(asset->frame_rate, video_read_length);
525 // video_read_length = MAX(video_read_length, 30);
526 video_read_length = 1;
529 // Guide video with audio
530 video_read_length = Units::to_int64(
531 (double)(audio_position + audio_read_length) /
538 if( video_position + video_read_length >= package->video_end ) {
540 video_read_length = package->video_end - video_position;
543 // Calculate samples rendered for progress bar.
545 samples_rendered = Units::round((double)video_read_length /
551 if( need_video && !result ) do_video();
552 if( need_audio && !result ) do_audio();
554 if( debug ) PRINT_TRACE
556 // Calculate frames per second for the renderfarm table.
557 total_samples_rendered += samples_rendered;
558 if( !video_done && timer->get_difference() > 30000 ) {
559 frames_per_second = (double)total_samples_rendered *
562 ((double)timer->get_difference() / 1000);
564 set_progress(samples_rendered);
567 if( !result && progress_cancelled() ) result = 1;
569 // audio_read_length, video_read_length, samples_rendered, result);
573 result = get_result();
577 frames_per_second = (double)(package->video_end - package->video_start) /
578 ((double)timer->get_difference() / 1000);
613 // Try to copy the compressed frame directly from the input to output files
614 // Return 1 on failure and 0 on success
615 int PackageRenderer::direct_frame_copy(EDL *edl,
616 int64_t &video_position,
620 Track *playable_track = 0;
621 Edit *playable_edit = 0;
623 //printf("Render::direct_frame_copy 1\n");
624 if( direct_copy_possible(edl,
629 // Switch to direct copying
630 if( !direct_frame_copying ) {
631 if( video_write_position ) {
632 error |= file->write_video_buffer(video_write_position);
633 video_write_position = 0;
635 file->stop_video_thread();
636 direct_frame_copying = 1;
638 //printf("Render::direct_frame_copy 2\n");
640 if( !package->use_brender ) {
641 error |= ((VEdit*)playable_edit)->read_frame(compressed_output,
648 //printf("Render::direct_frame_copy %d %d\n", __LINE__, compressed_output->get_compressed_size());
652 if( !error && video_preroll > 0 ) {
657 if( package->use_brender ) {
658 //printf("PackageRenderer::direct_frame_copy 1\n");
659 error = set_video_map(video_position, BRender::SCANNED);
660 //printf("PackageRenderer::direct_frame_copy 10 %d\n", error);
663 VFrame ***temp_output = new VFrame**[1];
664 temp_output[0] = new VFrame*[1];
665 temp_output[0][0] = compressed_output;
666 error = file->write_frames(temp_output, 1);
667 delete [] temp_output[0];
668 delete [] temp_output;
677 int PackageRenderer::direct_copy_possible(EDL *edl,
678 int64_t current_position,
679 Track* &playable_track, // The one track which is playable
680 Edit* &playable_edit, // The edit which is playing
681 File *file) // Output file
684 int total_playable_tracks = 0;
685 Track* current_track;
687 // Number of playable tracks must equal 1
688 for( current_track = edl->tracks->first;
689 current_track && result;
690 current_track = current_track->next ) {
691 if( current_track->data_type == TRACK_VIDEO ) {
692 if( playable_tracks->is_playable(current_track,
696 playable_track = current_track;
697 total_playable_tracks++;
702 //printf("Render::direct_copy_possible 1 %d\n", result);
703 if( total_playable_tracks != 1 ) result = 0;
704 //printf("Render::direct_copy_possible 2 %d\n", result);
706 // Edit must have a source file
707 // TODO: descend into nested EDL's
709 //printf("Render::direct_copy_possible 3 %d\n", result);
710 playable_edit = playable_track->edits->get_playable_edit(current_position, 1);
711 //printf("Render::direct_copy_possible 4 %d %p\n", result, playable_edit);
716 // Source file must be able to copy to destination file.
717 // Source file must be same size as project output.
719 if( !file->can_copy_from(playable_edit->asset,
720 current_position + playable_track->nudge,
721 edl->session->output_w,
722 edl->session->output_h) )
725 //printf("Render::direct_copy_possible 6 %d\n", result);
727 // Test conditions mutual between vrender.C and this.
729 !playable_track->direct_copy_possible(current_position, PLAY_FORWARD, 1) )
731 //printf("Render::direct_copy_possible 7 %d\n", result);
744 int PackageRenderer::get_master()
749 // Get result status from server
750 int PackageRenderer::get_result()
755 void PackageRenderer::set_result(int value)
759 void PackageRenderer::set_progress(int64_t value)
763 int PackageRenderer::set_video_map(int64_t position, int value)
768 int PackageRenderer::progress_cancelled()