4 * Copyright (C) 1997-2014 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
24 #include "bcsignals.h"
28 #include "condition.h"
31 #include "edlsession.h"
33 #include "framecache.h"
36 #include "mwindowgui.h"
37 #include "renderengine.h"
38 #include "resourcethread.h"
39 #include "resourcepixmap.h"
41 #include "timelinepane.h"
42 #include "trackcanvas.h"
43 #include "transportque.h"
46 #include "wavecache.h"
51 ResourceThreadItem::ResourceThreadItem(ResourcePixmap *pixmap,
57 this->pane_number = pane_number;
58 this->data_type = data_type;
59 this->pixmap = pixmap;
60 this->indexable = indexable;
62 // Assets are garbage collected so they don't need to be replicated.
63 this->operation_count = operation_count;
64 indexable->Garbage::add_user();
68 ResourceThreadItem::~ResourceThreadItem()
70 indexable->Garbage::remove_user();
79 VResourceThreadItem::VResourceThreadItem(ResourcePixmap *pixmap,
90 : ResourceThreadItem(pixmap,
96 this->picon_x = picon_x;
97 this->picon_y = picon_y;
98 this->picon_w = picon_w;
99 this->picon_h = picon_h;
100 this->frame_rate = frame_rate;
101 this->position = position;
105 VResourceThreadItem::~VResourceThreadItem()
116 AResourceThreadItem::AResourceThreadItem(ResourcePixmap *pixmap,
118 Indexable *indexable,
124 : ResourceThreadItem(pixmap,
131 this->channel = channel;
136 AResourceThreadItem::~AResourceThreadItem()
156 ResourceThread::ResourceThread(MWindow *mwindow, MWindowGUI *gui)
159 //printf("ResourceThread::ResourceThread %d %p\n", __LINE__, this);
160 this->mwindow = mwindow;
166 draw_lock = new Condition(0, "ResourceThread::draw_lock", 0);
167 item_lock = new Mutex("ResourceThread::item_lock");
169 for(int i = 0; i < MAXCHANNELS; i++)
177 render_engine_id = -1;
185 ResourceThread::~ResourceThread()
193 for(int i = 0; i < MAXCHANNELS; i++)
194 delete temp_buffer[i];
196 delete render_engine;
197 if( audio_asset ) audio_asset->remove_user();
198 if( video_asset ) video_asset->remove_user();
201 void ResourceThread::create_objects()
207 void ResourceThread::add_picon(ResourcePixmap *pixmap,
216 Indexable *indexable)
218 item_lock->lock("ResourceThread::item_lock");
220 items.append(new VResourceThreadItem(pixmap,
234 void ResourceThread::add_wave(ResourcePixmap *pixmap,
236 Indexable *indexable,
239 int64_t source_start,
242 item_lock->lock("ResourceThread::item_lock");
244 items.append(new AResourceThreadItem(pixmap,
255 void ResourceThread::reset(int pane_number)
257 item_lock->lock("ResourceThread::reset");
258 ResourceThreadItem *item = items.first;
260 ResourceThreadItem *next_item = item->next;
261 if( item->pane_number == pane_number ) delete item;
276 void ResourceThread::stop_draw(int reset)
281 item_lock->lock("ResourceThread::stop_draw");
283 //printf("ResourceThread::stop_draw %d %d\n", __LINE__, reset);
284 //BC_Signals::dump_stack();
286 ResourceThreadItem *item;
287 while( (item=items.last) != 0 ) delete item;
297 void ResourceThread::start_draw()
300 // Tag last audio item to cause refresh.
301 ResourceThreadItem *item = items.last;
302 while( item && item->data_type!=TRACK_AUDIO ) item = item->previous;
303 if( item ) item->last = 1;
308 void ResourceThread::run()
313 draw_lock->lock("ResourceThread::run");
317 item_lock->lock("ResourceThread::run");
318 ResourceThreadItem *item = items.first;
319 items.remove_pointer(item);
321 //printf("ResourceThread::run %d %d\n", __LINE__, items.size());
324 switch( item->data_type ) {
326 do_video((VResourceThreadItem*)item);
329 do_audio((AResourceThreadItem*)item);
338 mwindow->age_caches();
342 void ResourceThread::stop()
353 void ResourceThread::open_render_engine(EDL *nested_edl,
357 if(render_engine && render_engine_id != nested_edl->id)
359 delete render_engine;
365 TransportCommand command;
367 command.command = NORMAL_FWD;
369 command.command = CURRENT_FRAME;
370 command.get_edl()->copy_all(nested_edl);
371 command.change_type = CHANGE_ALL;
372 command.realtime = 0;
373 render_engine = new RenderEngine(0,
374 mwindow->preferences, 0, 0);
375 render_engine_id = nested_edl->id;
376 render_engine->set_vcache(mwindow->video_cache);
377 render_engine->set_acache(mwindow->audio_cache);
378 render_engine->arm_command(&command);
382 File *ResourceThread::get_audio_source(Asset *asset)
384 if( interrupted ) asset = 0;
386 if( audio_asset && audio_asset != asset && (!asset ||
387 strcmp(audio_asset->path, asset->path)) )
389 mwindow->audio_cache->check_in(audio_asset);
391 audio_asset->remove_user();
395 if( !audio_asset && asset )
398 audio_asset->add_user();
399 audio_source = mwindow->audio_cache->check_out(asset, mwindow->edl);
404 File *ResourceThread::get_video_source(Asset *asset)
406 if( interrupted ) asset = 0;
408 if( video_asset && video_asset != asset && (!asset ||
409 strcmp(video_asset->path, asset->path)) )
411 mwindow->video_cache->check_in(video_asset);
413 video_asset->remove_user();
417 if( !video_asset && asset )
420 video_asset->add_user();
421 video_source = mwindow->video_cache->check_out(asset, mwindow->edl);
426 void ResourceThread::do_video(VResourceThreadItem *item)
431 int source_cmodel = -1;
433 if(item->indexable->is_asset)
435 Asset *asset = (Asset*)item->indexable;
436 source_w = asset->width;
437 source_h = asset->height;
438 source_id = asset->id;
439 source_cmodel = BC_RGB888;
443 EDL *nested_edl = (EDL*)item->indexable;
444 source_w = nested_edl->session->output_w;
445 source_h = nested_edl->session->output_h;
446 source_id = nested_edl->id;
447 source_cmodel = nested_edl->session->color_model;
451 (temp_picon->get_w() != source_w ||
452 temp_picon->get_h() != source_h ||
453 temp_picon->get_color_model() != source_cmodel))
461 temp_picon = new VFrame(0, -1, source_w, source_h, source_cmodel, -1);
464 // Get temporary to copy cached frame to
466 (temp_picon2->get_w() != item->picon_w ||
467 temp_picon2->get_h() != item->picon_h))
475 temp_picon2 = new VFrame( item->picon_w, item->picon_h, BC_RGB888, 0);
480 // Search frame cache again.
482 VFrame *picon_frame = 0;
483 int need_conversion = 0;
487 picon_frame = mwindow->frame_cache->get_frame_ptr(item->position,
488 item->layer, item->frame_rate, BC_RGB888,
489 item->picon_w, item->picon_h, source_id);
490 //printf("search cache %ld,%d,%f,%dx%d,%d = %p\n",
491 // item->position, item->layer, item->frame_rate,
492 // item->picon_w, item->picon_h, source_id, picon_frame);
494 temp_picon2->copy_from(picon_frame);
495 // Unlock the get_frame_ptr command
496 mwindow->frame_cache->unlock();
499 if(!item->indexable->is_asset)
501 nested_edl = (EDL*)item->indexable;
502 open_render_engine(nested_edl, 0, 1);
504 int64_t source_position = (int64_t)(item->position *
505 nested_edl->session->frame_rate /
507 if(render_engine->vrender)
508 render_engine->vrender->process_buffer(
517 asset = (Asset*)item->indexable;
518 File *source = get_video_source(asset);
522 source->set_layer(item->layer);
523 int64_t normalized_position = (int64_t)(item->position *
526 source->set_video_position(normalized_position,
529 source->read_frame(temp_picon);
536 picon_frame = new VFrame(item->picon_w, item->picon_h, BC_RGB888, 0);
537 BC_CModels::transfer(picon_frame->get_rows(), temp_picon->get_rows(),
539 0, 0, temp_picon->get_w(), temp_picon->get_h(),
540 0, 0, picon_frame->get_w(), picon_frame->get_h(),
541 source_cmodel, BC_RGB888, 0,
542 temp_picon->get_bytes_per_line(),
543 picon_frame->get_bytes_per_line());
544 temp_picon2->copy_from(picon_frame);
545 mwindow->frame_cache->put_frame(picon_frame, item->position, item->layer,
546 mwindow->edl->session->frame_rate, 0, item->indexable);
554 mwindow->gui->lock_window("ResourceThread::do_video");
556 // It was interrupted while waiting.
559 mwindow->gui->unlock_window();
565 // Test for pixmap existence first
566 if(item->operation_count == operation_count)
568 ArrayList<ResourcePixmap*> &resource_pixmaps = gui->resource_pixmaps;
569 int i = resource_pixmaps.total;
570 while( --i >= 0 && resource_pixmaps[i] != item->pixmap );
572 item->pixmap->draw_vframe(temp_picon2,
580 mwindow->gui->update(0, IGNORE_THREAD, 0, 0, 0, 0, 0);
584 mwindow->gui->unlock_window();
588 #define BUFFERSIZE 65536
589 void ResourceThread::do_audio(AResourceThreadItem *item)
592 WaveCacheItem *wave_item;
596 if(debug) printf("ResourceThread::do_audio %d\n", __LINE__);
597 if((wave_item = mwindow->wave_cache->get_wave(item->indexable->id,
598 item->channel, item->start, item->end)))
600 high = wave_item->high;
601 low = wave_item->low;
602 mwindow->wave_cache->unlock();
606 int first_sample = 1;
607 int64_t start = item->start;
608 int64_t end = item->end;
609 if(start == end) end = start + 1;
610 double *buffer_samples = !audio_buffer ? 0 :
611 audio_buffer->get_data();
613 if(debug) printf("ResourceThread::do_audio %d\n", __LINE__);
614 for(int64_t sample = start; sample < end; sample++)
617 // Get value from previous buffer
619 item->channel == audio_channel &&
620 item->indexable->id == audio_asset_id &&
621 sample >= audio_start &&
622 sample < audio_start + audio_samples)
630 audio_buffer = new Samples(BUFFERSIZE);
631 buffer_samples = audio_buffer->get_data();
634 int64_t total_samples = item->indexable->get_audio_samples();
635 int fragment = BUFFERSIZE;
636 if(fragment + sample > total_samples)
637 fragment = total_samples - sample;
639 if(!item->indexable->is_asset)
641 if(debug) printf("ResourceThread::do_audio %d\n", __LINE__);
642 open_render_engine((EDL*)item->indexable, 1, 0);
643 if(debug) printf("ResourceThread::do_audio %d %p\n", __LINE__, render_engine);
644 if(render_engine->arender)
646 if(debug) printf("ResourceThread::do_audio %d\n", __LINE__);
647 int source_channels = item->indexable->get_audio_channels();
648 if(debug) printf("ResourceThread::do_audio %d\n", __LINE__);
649 for(int i = 0; i < MAXCHANNELS; i++)
651 if(i < source_channels &&
654 temp_buffer[i] = new Samples(BUFFERSIZE);
657 if(i >= source_channels &&
660 delete temp_buffer[i];
666 if(debug) printf("ResourceThread::do_audio %d\n", __LINE__);
667 render_engine->arender->process_buffer(
671 if(debug) printf("ResourceThread::do_audio %d\n", __LINE__);
672 memcpy(buffer_samples,
673 temp_buffer[item->channel]->get_data(),
674 fragment * sizeof(double));
678 if(debug) printf("ResourceThread::do_audio %d %d\n", __LINE__, fragment);
679 if(fragment > 0) bzero(buffer_samples, sizeof(double) * fragment);
680 if(debug) printf("ResourceThread::do_audio %d\n", __LINE__);
686 Asset *asset = (Asset*)item->indexable;
687 File *source = get_audio_source(asset);
691 source->set_channel(item->channel);
692 source->set_audio_position(sample);
693 source->read_samples(audio_buffer, fragment);
696 audio_asset_id = item->indexable->id;
697 audio_channel = item->channel;
698 audio_start = sample;
699 audio_samples = fragment;
703 value = buffer_samples[sample - audio_start];
718 if(debug) printf("ResourceThread::do_audio %d\n", __LINE__);
720 // If it's a nested EDL, store all the channels
721 mwindow->wave_cache->put_wave(item->indexable,
727 if(debug) printf("ResourceThread::do_audio %d\n", __LINE__);
729 if(debug) printf("ResourceThread::do_audio %d\n", __LINE__);
735 if(debug) printf("ResourceThread::do_audio %d\n", __LINE__);
737 mwindow->gui->lock_window("ResourceThread::do_audio");
740 mwindow->gui->unlock_window();
744 if(debug) printf("ResourceThread::do_audio %d\n", __LINE__);
745 if(item->operation_count == operation_count)
748 // Test for pixmap existence first
749 ArrayList<ResourcePixmap*> &resource_pixmaps = gui->resource_pixmaps;
750 int i = resource_pixmaps.total;
751 while( --i >= 0 && resource_pixmaps[i] != item->pixmap );
754 if(prev_x == item->x - 1)
756 high = MAX(high, prev_l);
757 low = MIN(low, prev_h);
762 if(gui->pane[item->pane_number])
763 item->pixmap->draw_wave(
764 gui->pane[item->pane_number]->canvas,
768 if(timer->get_difference() > 250 || item->last)
770 mwindow->gui->update(0, IGNORE_THREAD, 0, 0, 0, 0, 0);
775 if(debug) printf("ResourceThread::do_audio %d\n", __LINE__);
777 mwindow->gui->unlock_window();