r972: Fix aspect ratio of YUV4MPEG streams.
[cinelerra_cv/ct.git] / cinelerra / resourcethread.C
bloba6cbdad691f586e609a2d41fe9a4c05e7569a92b
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 *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         asset->GarbageObject::add_user();
32         last = 0;
35 ResourceThreadItem::~ResourceThreadItem()
37         asset->GarbageObject::remove_user();
46 VResourceThreadItem::VResourceThreadItem(ResourcePixmap *pixmap, 
47         int picon_x, 
48         int picon_y, 
49         int picon_w,
50         int picon_h,
51         double frame_rate,
52         int64_t position,
53         int layer,
54         Asset *asset,
55         int operation_count)
56  : ResourceThreadItem(pixmap, asset, TRACK_VIDEO, operation_count)
58         this->picon_x = picon_x;
59         this->picon_y = picon_y;
60         this->picon_w = picon_w;
61         this->picon_h = picon_h;
62         this->frame_rate = frame_rate;
63         this->position = position;
64         this->layer = layer;
67 VResourceThreadItem::~VResourceThreadItem()
78 AResourceThreadItem::AResourceThreadItem(ResourcePixmap *pixmap, 
79         Asset *asset,
80         int x,
81         int channel,
82         int64_t start,
83         int64_t end,
84         int operation_count)
85  : ResourceThreadItem(pixmap, asset, TRACK_AUDIO, operation_count)
87         this->x = x;
88         this->channel = channel;
89         this->start = start;
90         this->end = end;
93 AResourceThreadItem::~AResourceThreadItem()
113 ResourceThread::ResourceThread(MWindow *mwindow)
115         this->mwindow = mwindow;
116         interrupted = 1;
117         temp_picon = 0;
118         temp_picon2 = 0;
119         draw_lock = new Condition(0, "ResourceThread::draw_lock", 0);
120 //      interrupted_lock = new Condition(0, "ResourceThread::interrupted_lock", 0);
121         item_lock = new Mutex("ResourceThread::item_lock");
122         audio_buffer = 0;
123         timer = new Timer;
124         prev_x = -1;
125         prev_h = 0;
126         prev_l = 0;
127         operation_count = 0;
130 ResourceThread::~ResourceThread()
132         delete draw_lock;
133 //      delete interrupted_lock;
134         delete item_lock;
135         delete temp_picon;
136         delete temp_picon2;
137         delete [] audio_buffer;
138         delete timer;
141 void ResourceThread::create_objects()
143         Thread::start();
146 void ResourceThread::add_picon(ResourcePixmap *pixmap, 
147         int picon_x, 
148         int picon_y, 
149         int picon_w,
150         int picon_h,
151         double frame_rate,
152         int64_t position,
153         int layer,
154         Asset *asset)
156         item_lock->lock("ResourceThread::item_lock");
158         items.append(new VResourceThreadItem(pixmap, 
159                 picon_x, 
160                 picon_y, 
161                 picon_w,
162                 picon_h,
163                 frame_rate,
164                 position,
165                 layer,
166                 asset,
167                 operation_count));
168         item_lock->unlock();
171 void ResourceThread::add_wave(ResourcePixmap *pixmap,
172         Asset *asset,
173         int x,
174         int channel,
175         int64_t source_start,
176         int64_t source_end)
178         item_lock->lock("ResourceThread::item_lock");
180         items.append(new AResourceThreadItem(pixmap, 
181                 asset,
182                 x,
183                 channel,
184                 source_start,
185                 source_end,
186                 operation_count));
187         item_lock->unlock();
200 void ResourceThread::stop_draw(int reset)
202         if(!interrupted)
203         {
204                 interrupted = 1;
205                 item_lock->lock("ResourceThread::stop_draw");
206                 if(reset) items.remove_all_objects();
207                 operation_count++;
208                 item_lock->unlock();
209                 prev_x = -1;
210                 prev_h = 0;
211                 prev_l = 0;
212         }
215 void ResourceThread::start_draw()
217         interrupted = 0;
218 // Tag last audio item to cause refresh.
219         for(int i = items.total - 1; i >= 0; i--)
220         {
221                 ResourceThreadItem *item = items.values[i];
222                 if(item->data_type == TRACK_AUDIO)
223                 {
224                         item->last = 1;
225                         break;
226                 }
227         }
228         timer->update();
229         draw_lock->unlock();
232 void ResourceThread::run()
234         while(1)
235         {
237                 draw_lock->lock("ResourceThread::run");
240                 while(!interrupted)
241                 {
243 // Pull off item
244                         item_lock->lock("ResourceThread::run");
245                         int total_items = items.total;
246                         ResourceThreadItem *item = 0;
247                         if(items.total) 
248                         {
249                                 item = items.values[0];
250                                 items.remove_number(0);
251                         }
252                         item_lock->unlock();
254                         if(!total_items) break;
257                         if(item->data_type == TRACK_VIDEO)
258                         {
260                                 do_video((VResourceThreadItem*)item);
261                         }
262                         else
263                         if(item->data_type == TRACK_AUDIO)
264                         {
265                                 do_audio((AResourceThreadItem*)item);
266                         }
268                         delete item;
269                 }
270         }
276 void ResourceThread::do_video(VResourceThreadItem *item)
278         if(temp_picon &&
279                 (temp_picon->get_w() != item->asset->width ||
280                 temp_picon->get_h() != item->asset->height))
281         {
282                 delete temp_picon;
283                 temp_picon = 0;
284         }
286         if(!temp_picon)
287         {
288                 temp_picon = new VFrame(0, 
289                         item->asset->width, 
290                         item->asset->height, 
291                         BC_RGB888);
292         }
294 // Get temporary to copy cached frame to
295         if(temp_picon2 &&
296                 (temp_picon2->get_w() != item->picon_w ||
297                 temp_picon2->get_h() != item->picon_h))
298         {
299                 delete temp_picon2;
300                 temp_picon2 = 0;
301         }
303         if(!temp_picon2)
304         {
305                 temp_picon2 = new VFrame(0, 
306                         item->picon_w, 
307                         item->picon_h, 
308                         BC_RGB888);
309         }
313 // Search frame cache again.
315         VFrame *picon_frame = 0;
317         if((picon_frame = mwindow->frame_cache->get_frame_ptr(item->position,
318                 item->layer,
319                 item->frame_rate,
320                 BC_RGB888,
321                 item->picon_w,
322                 item->picon_h,
323                 item->asset->id)) != 0)
324         {
325                 temp_picon2->copy_from(picon_frame);
326 // Unlock the get_frame_ptr command
327                 mwindow->frame_cache->unlock();
328         }
329         else
330         {
332                 File *source = mwindow->video_cache->check_out(item->asset,
333                         mwindow->edl);
334                 if(!source) 
335                 {
336                         return;
337                 }
338                 source->set_layer(item->layer);
339                 source->set_video_position(item->position, 
340                         item->frame_rate);
342                 source->read_frame(temp_picon);
343                 picon_frame = new VFrame(0, item->picon_w, item->picon_h, BC_RGB888);
344                 cmodel_transfer(picon_frame->get_rows(),
345                         temp_picon->get_rows(),
346                         0,
347                         0,
348                         0,
349                         0,
350                         0,
351                         0,
352                         0,
353                         0, 
354                         temp_picon->get_w(),
355                         temp_picon->get_h(),
356                         0,
357                         0,
358                         picon_frame->get_w(), 
359                         picon_frame->get_h(),
360                         BC_RGB888,
361                         BC_RGB888,
362                         0,
363                         temp_picon->get_bytes_per_line(),
364                         picon_frame->get_bytes_per_line());
365                 temp_picon2->copy_from(picon_frame);
366                 mwindow->frame_cache->put_frame(picon_frame, 
367                         item->position,
368                         item->layer,
369                         mwindow->edl->session->frame_rate,
370                         0,
371                         item->asset);
372                 mwindow->video_cache->check_in(item->asset);
373         }
376 // Allow escape here
377         if(interrupted) 
378         {
379                 return;
380         }
383 // Draw the picon
384         mwindow->gui->lock_window("ResourceThread::do_video");
386         if(interrupted)
387         {
388                 mwindow->gui->unlock_window();
389                 return;
390         }
394 // Test for pixmap existence first
395         if(item->operation_count == operation_count)
396         {
397                 int exists = 0;
398                 for(int i = 0; i < mwindow->gui->canvas->resource_pixmaps.total; i++)
399                 {
400                         if(mwindow->gui->canvas->resource_pixmaps.values[i] == item->pixmap)
401                                 exists = 1;
402                 }
403                 if(exists)
404                 {
405                         item->pixmap->draw_vframe(temp_picon2, 
406                                 item->picon_x, 
407                                 item->picon_y, 
408                                 item->picon_w, 
409                                 item->picon_h, 
410                                 0, 
411                                 0);
412                         mwindow->gui->update(0, 3, 0, 0, 0, 0, 0);
413                 }
414         }
416         mwindow->gui->unlock_window();
420 #define BUFFERSIZE 65536
421 void ResourceThread::do_audio(AResourceThreadItem *item)
423 // Search again
424         WaveCacheItem *wave_item;
425         double high;
426         double low;
427         
428         if((wave_item = mwindow->wave_cache->get_wave(item->asset->id,
429                 item->channel,
430                 item->start,
431                 item->end)))
432         {
433                 high = wave_item->high;
434                 low = wave_item->low;
435                 mwindow->wave_cache->unlock();
436         }
437         else
438         {
439                 int first_sample = 1;
440                 int64_t start = item->start;
441                 int64_t end = item->end;
442                 if(start == end) end = start + 1;
443                 
444                 for(int64_t sample = start; sample < end; sample++)
445                 {
446                         double value;
447 // Get value from previous buffer
448                         if(audio_buffer && 
449                                 item->channel == audio_channel &&
450                                 item->asset->id == audio_asset_id &&
451                                 sample >= audio_start &&
452                                 sample < audio_start + audio_samples)
453                         {
454                                 ;
455                         }
456                         else
457 // Load new buffer
458                         {
459                                 File *source = mwindow->audio_cache->check_out(item->asset,
460                                         mwindow->edl);
461                                 if(!source)
462                                         return;
463                                         
464                                 source->set_channel(item->channel);
465                                 source->set_audio_position(sample, item->asset->sample_rate);
466                                 int64_t total_samples = source->get_audio_length(-1);
467                                 if(!audio_buffer) audio_buffer = new double[BUFFERSIZE];
468                                 int fragment = BUFFERSIZE;
469                                 if(fragment + sample > total_samples)
470                                         fragment = total_samples - sample;
471                                 source->read_samples(audio_buffer, fragment, item->asset->sample_rate);
472                                 audio_channel = item->channel;
473                                 audio_start = sample;
474                                 audio_samples = fragment;
475                                 audio_asset_id = item->asset->id;
476                                 mwindow->audio_cache->check_in(item->asset);
477                         }
480                         value = audio_buffer[sample - audio_start];
481                         if(first_sample)
482                         {
483                                 high = low = value;
484                                 first_sample = 0;
485                         }
486                         else
487                         {
488                                 if(value > high) 
489                                         high = value;
490                                 else
491                                 if(value < low)
492                                         low = value;
493                         }
494                 }
496                 mwindow->wave_cache->put_wave(item->asset,
497                         item->channel,
498                         item->start,
499                         item->end,
500                         high,
501                         low);
502         }
504 // Allow escape here
505         if(interrupted)
506                 return;
508 // Draw the column
509         mwindow->gui->lock_window("ResourceThread::do_audio");
510         if(interrupted)
511         {
512                 mwindow->gui->unlock_window();
513                 return;
514         }
516         if(item->operation_count == operation_count)
517         {
519 // Test for pixmap existence first
520                 int exists = 0;
521                 for(int i = 0; i < mwindow->gui->canvas->resource_pixmaps.total; i++)
522                 {
523                         if(mwindow->gui->canvas->resource_pixmaps.values[i] == item->pixmap)
524                                 exists = 1;
525                 }
527                 if(exists)
528                 {
529                         if(prev_x == item->x - 1)
530                         {
531                                 high = MAX(high, prev_l);
532                                 low = MIN(low, prev_h);
533                         }
534                         prev_x = item->x;
535                         prev_h = high;
536                         prev_l = low;
537                         item->pixmap->draw_wave(item->x, high, low);
538                         if(timer->get_difference() > 250 || item->last)
539                         {
540                                 mwindow->gui->update(0, 3, 0, 0, 0, 0, 0);
541                                 timer->update();
542                         }
543                 }
544         }
546         mwindow->gui->unlock_window();