Merge branch 'ct' of git.pipapo.org:cinelerra-ct into ct
[cinelerra_cv/ct.git] / cinelerra / resourcethread.C
blob674ef21865e24b49d553b1ce27aeb4d99c197f93
1 #include "asset.h"
2 #include "bcsignals.h"
3 #include "bctimer.h"
4 #include "cache.h"
5 #include "clip.h"
6 #include "condition.h"
7 #include "datatype.h"
8 #include "edl.h"
9 #include "edlsession.h"
10 #include "file.h"
11 #include "framecache.h"
12 #include "mutex.h"
13 #include "mwindow.h"
14 #include "mwindowgui.h"
15 #include "resourcethread.h"
16 #include "resourcepixmap.h"
17 #include "trackcanvas.h"
18 #include "vframe.h"
19 #include "wavecache.h"
22 ResourceThreadItem::ResourceThreadItem(ResourcePixmap *pixmap, 
23         Asset_GC asset,
24         int data_type,
25         int operation_count)
27         this->data_type = data_type;
28         this->pixmap = pixmap;
29         this->asset = asset;
30         this->operation_count = operation_count;
31         last = 0;
39 VResourceThreadItem::VResourceThreadItem(ResourcePixmap *pixmap, 
40         int picon_x, 
41         int picon_y, 
42         int picon_w,
43         int picon_h,
44         double frame_rate,
45         int64_t position,
46         int layer,
47         Asset_GC asset,
48         int operation_count)
49  : ResourceThreadItem(pixmap, asset, TRACK_VIDEO, operation_count)
51         this->picon_x = picon_x;
52         this->picon_y = picon_y;
53         this->picon_w = picon_w;
54         this->picon_h = picon_h;
55         this->frame_rate = frame_rate;
56         this->position = position;
57         this->layer = layer;
60 VResourceThreadItem::~VResourceThreadItem()
71 AResourceThreadItem::AResourceThreadItem(ResourcePixmap *pixmap, 
72         Asset_GC asset,
73         int x,
74         int channel,
75         int64_t start,
76         int64_t end,
77         int operation_count)
78  : ResourceThreadItem(pixmap, asset, TRACK_AUDIO, operation_count)
80         this->x = x;
81         this->channel = channel;
82         this->start = start;
83         this->end = end;
86 AResourceThreadItem::~AResourceThreadItem()
106 ResourceThread::ResourceThread(MWindow *mwindow)
108         this->mwindow = mwindow;
109         interrupted = 1;
110         temp_picon = 0;
111         temp_picon2 = 0;
112         draw_lock = new Condition(0, "ResourceThread::draw_lock", 0);
113 //      interrupted_lock = new Condition(0, "ResourceThread::interrupted_lock", 0);
114         item_lock = new Mutex("ResourceThread::item_lock");
115         audio_buffer = 0;
116         timer = new Timer;
117         prev_x = -1;
118         prev_h = 0;
119         prev_l = 0;
120         operation_count = 0;
123 ResourceThread::~ResourceThread()
125         delete draw_lock;
126 //      delete interrupted_lock;
127         delete item_lock;
128         delete temp_picon;
129         delete temp_picon2;
130         delete [] audio_buffer;
131         delete timer;
134 void ResourceThread::create_objects()
136         Thread::start();
139 void ResourceThread::add_picon(ResourcePixmap *pixmap, 
140         int picon_x, 
141         int picon_y, 
142         int picon_w,
143         int picon_h,
144         double frame_rate,
145         int64_t position,
146         int layer,
147         Asset_GC asset)
149         item_lock->lock("ResourceThread::item_lock");
151         items.append(new VResourceThreadItem(pixmap, 
152                 picon_x, 
153                 picon_y, 
154                 picon_w,
155                 picon_h,
156                 frame_rate,
157                 position,
158                 layer,
159                 asset,
160                 operation_count));
161         item_lock->unlock();
164 void ResourceThread::add_wave(ResourcePixmap *pixmap,
165         Asset_GC asset,
166         int x,
167         int channel,
168         int64_t source_start,
169         int64_t source_end)
171         item_lock->lock("ResourceThread::item_lock");
173         items.append(new AResourceThreadItem(pixmap, 
174                 asset,
175                 x,
176                 channel,
177                 source_start,
178                 source_end,
179                 operation_count));
180         item_lock->unlock();
193 void ResourceThread::stop_draw(int reset)
195         if(!interrupted)
196         {
197                 interrupted = 1;
198                 item_lock->lock("ResourceThread::stop_draw");
199                 if(reset) items.remove_all_objects();
200                 operation_count++;
201                 item_lock->unlock();
202                 prev_x = -1;
203                 prev_h = 0;
204                 prev_l = 0;
205         }
208 void ResourceThread::start_draw()
210         interrupted = 0;
211 // Tag last audio item to cause refresh.
212         for(int i = items.total - 1; i >= 0; i--)
213         {
214                 ResourceThreadItem *item = items.values[i];
215                 if(item->data_type == TRACK_AUDIO)
216                 {
217                         item->last = 1;
218                         break;
219                 }
220         }
221         timer->update();
222         draw_lock->unlock();
225 void ResourceThread::run()
227         while(1)
228         {
230                 draw_lock->lock("ResourceThread::run");
233                 while(!interrupted)
234                 {
236 // Pull off item
237                         item_lock->lock("ResourceThread::run");
238                         int total_items = items.total;
239                         ResourceThreadItem *item = 0;
240                         if(items.total) 
241                         {
242                                 item = items.values[0];
243                                 items.remove_number(0);
244                         }
245                         item_lock->unlock();
247                         if(!total_items) break;
250                         if(item->data_type == TRACK_VIDEO)
251                         {
253                                 do_video((VResourceThreadItem*)item);
254                         }
255                         else
256                         if(item->data_type == TRACK_AUDIO)
257                         {
258                                 do_audio((AResourceThreadItem*)item);
259                         }
261                         delete item;
262                 }
263         }
269 void ResourceThread::do_video(VResourceThreadItem *item)
271         if(temp_picon &&
272                 (temp_picon->get_w() != item->asset->width ||
273                 temp_picon->get_h() != item->asset->height))
274         {
275                 delete temp_picon;
276                 temp_picon = 0;
277         }
279         if(!temp_picon)
280         {
281                 temp_picon = new VFrame(0, 
282                         item->asset->width, 
283                         item->asset->height, 
284                         BC_RGB888);
285         }
287 // Get temporary to copy cached frame to
288         if(temp_picon2 &&
289                 (temp_picon2->get_w() != item->picon_w ||
290                 temp_picon2->get_h() != item->picon_h))
291         {
292                 delete temp_picon2;
293                 temp_picon2 = 0;
294         }
296         if(!temp_picon2)
297         {
298                 temp_picon2 = new VFrame(0, 
299                         item->picon_w, 
300                         item->picon_h, 
301                         BC_RGB888);
302         }
306 // Search frame cache again.
308         VFrame *picon_frame = 0;
310         if((picon_frame = mwindow->frame_cache->get_frame_ptr(item->position,
311                 item->layer,
312                 item->frame_rate,
313                 BC_RGB888,
314                 item->picon_w,
315                 item->picon_h,
316                 item->asset->id)) != 0)
317         {
318                 temp_picon2->copy_from(picon_frame);
319 // Unlock the get_frame_ptr command
320                 mwindow->frame_cache->unlock();
321         }
322         else
323         {
325                 File *source = mwindow->video_cache->check_out(item->asset,
326                         mwindow->edl);
327                 if(!source) 
328                 {
329                         return;
330                 }
331                 source->set_layer(item->layer);
332                 source->set_video_position(item->position, 
333                         item->frame_rate);
335                 source->read_frame(temp_picon);
336                 picon_frame = new VFrame(0, item->picon_w, item->picon_h, BC_RGB888);
337                 cmodel_transfer(picon_frame->get_rows(),
338                         temp_picon->get_rows(),
339                         0,
340                         0,
341                         0,
342                         0,
343                         0,
344                         0,
345                         0,
346                         0, 
347                         temp_picon->get_w(),
348                         temp_picon->get_h(),
349                         0,
350                         0,
351                         picon_frame->get_w(), 
352                         picon_frame->get_h(),
353                         BC_RGB888,
354                         BC_RGB888,
355                         0,
356                         temp_picon->get_bytes_per_line(),
357                         picon_frame->get_bytes_per_line());
358                 temp_picon2->copy_from(picon_frame);
359                 mwindow->frame_cache->put_frame(picon_frame, 
360                         item->position,
361                         item->layer,
362                         mwindow->edl->session->frame_rate,
363                         0,
364                         item->asset);
365                 mwindow->video_cache->check_in(item->asset);
366         }
369 // Allow escape here
370         if(interrupted) 
371         {
372                 return;
373         }
376 // Draw the picon
377         mwindow->gui->lock_window("ResourceThread::do_video");
379         if(interrupted)
380         {
381                 mwindow->gui->unlock_window();
382                 return;
383         }
387 // Test for pixmap existence first
388         if(item->operation_count == operation_count)
389         {
390                 int exists = 0;
391                 for(int i = 0; i < mwindow->gui->canvas->resource_pixmaps.total; i++)
392                 {
393                         if(mwindow->gui->canvas->resource_pixmaps.values[i] == item->pixmap)
394                                 exists = 1;
395                 }
396                 if(exists)
397                 {
398                         item->pixmap->draw_vframe(temp_picon2, 
399                                 item->picon_x, 
400                                 item->picon_y, 
401                                 item->picon_w, 
402                                 item->picon_h, 
403                                 0, 
404                                 0);
405                         mwindow->gui->update(0, 3, 0, 0, 0, 0, 0);
406                 }
407         }
409         mwindow->gui->unlock_window();
413 #define BUFFERSIZE 65536
414 void ResourceThread::do_audio(AResourceThreadItem *item)
416 // Search again
417         WaveCacheItem *wave_item;
418         double high;
419         double low;
420         
421         if((wave_item = mwindow->wave_cache->get_wave(item->asset->id,
422                 item->channel,
423                 item->start,
424                 item->end)))
425         {
426                 high = wave_item->high;
427                 low = wave_item->low;
428                 mwindow->wave_cache->unlock();
429         }
430         else
431         {
432                 int first_sample = 1;
433                 int64_t start = item->start;
434                 int64_t end = item->end;
435                 if(start == end) end = start + 1;
436                 
437                 for(int64_t sample = start; sample < end; sample++)
438                 {
439                         double value;
440 // Get value from previous buffer
441                         if(audio_buffer && 
442                                 item->channel == audio_channel &&
443                                 item->asset->id == audio_asset_id &&
444                                 sample >= audio_start &&
445                                 sample < audio_start + audio_samples)
446                         {
447                                 ;
448                         }
449                         else
450 // Load new buffer
451                         {
452                                 File *source = mwindow->audio_cache->check_out(item->asset,
453                                         mwindow->edl);
454                                 if(!source)
455                                         return;
456                                         
457                                 source->set_channel(item->channel);
458                                 source->set_audio_position(sample, item->asset->sample_rate);
459                                 int64_t total_samples = source->get_audio_length(-1);
460                                 if(!audio_buffer) audio_buffer = new double[BUFFERSIZE];
461                                 int fragment = BUFFERSIZE;
462                                 if(fragment + sample > total_samples)
463                                         fragment = total_samples - sample;
464                                 source->read_samples(audio_buffer, fragment, item->asset->sample_rate);
465                                 audio_channel = item->channel;
466                                 audio_start = sample;
467                                 audio_samples = fragment;
468                                 audio_asset_id = item->asset->id;
469                                 mwindow->audio_cache->check_in(item->asset);
470                         }
473                         value = audio_buffer[sample - audio_start];
474                         if(first_sample)
475                         {
476                                 high = low = value;
477                                 first_sample = 0;
478                         }
479                         else
480                         {
481                                 if(value > high) 
482                                         high = value;
483                                 else
484                                 if(value < low)
485                                         low = value;
486                         }
487                 }
489                 mwindow->wave_cache->put_wave(item->asset,
490                         item->channel,
491                         item->start,
492                         item->end,
493                         high,
494                         low);
495         }
497 // Allow escape here
498         if(interrupted)
499                 return;
501 // Draw the column
502         mwindow->gui->lock_window("ResourceThread::do_audio");
503         if(interrupted)
504         {
505                 mwindow->gui->unlock_window();
506                 return;
507         }
509         if(item->operation_count == operation_count)
510         {
512 // Test for pixmap existence first
513                 int exists = 0;
514                 for(int i = 0; i < mwindow->gui->canvas->resource_pixmaps.total; i++)
515                 {
516                         if(mwindow->gui->canvas->resource_pixmaps.values[i] == item->pixmap)
517                                 exists = 1;
518                 }
520                 if(exists)
521                 {
522                         if(prev_x == item->x - 1)
523                         {
524                                 high = MAX(high, prev_l);
525                                 low = MIN(low, prev_h);
526                         }
527                         prev_x = item->x;
528                         prev_h = high;
529                         prev_l = low;
530                         item->pixmap->draw_wave(item->x, high, low);
531                         if(timer->get_difference() > 250 || item->last)
532                         {
533                                 mwindow->gui->update(0, 3, 0, 0, 0, 0, 0);
534                                 timer->update();
535                         }
536                 }
537         }
539         mwindow->gui->unlock_window();
547 //      Local Variables:
548 //      mode: C++
549 //      c-file-style: "linux"
550 //      End: