license header for review
[cinelerra_cv/ct.git] / cinelerra / resourcepixmap.C
blob4e187c7453b213bd9180d9df443c0fc344aa1fd2
1 #include "aedit.h"
2 #include "asset.h"
3 #include "asset.inc"
4 #include "cache.h"
5 #include "clip.h"
6 #include "colormodels.h"
7 #include "datatype.h"
8 #include "edit.h"
9 #include "edits.h"
10 #include "edl.h"
11 #include "edlsession.h"
12 #include "file.h"
13 #include "filesystem.h"
14 #include "framecache.h"
15 #include "indexfile.h"
16 #include "language.h"
17 #include "localsession.h"
18 #include "mwindow.h"
19 #include "resourcethread.h"
20 #include "resourcepixmap.h"
21 #include "theme.h"
22 #include "track.h"
23 #include "trackcanvas.h"
24 #include "vedit.h"
25 #include "vframe.h"
26 #include "wavecache.h"
29 ResourcePixmap::ResourcePixmap(MWindow *mwindow, 
30         TrackCanvas *canvas, 
31         Edit *edit, 
32         int w, 
33         int h)
34  : BC_Pixmap(canvas, w, h)
36         reset();
38         this->mwindow = mwindow;
39         this->canvas = canvas;
40         startsource = edit->startsource;
41         data_type = edit->track->data_type;
42         source_framerate = edit->asset->frame_rate;
43         project_framerate = edit->edl->session->frame_rate;
44         source_samplerate = edit->asset->sample_rate;
45         project_samplerate = edit->edl->session->sample_rate;
46         edit_id = edit->id;
49 ResourcePixmap::~ResourcePixmap()
54 void ResourcePixmap::reset()
56         edit_x = 0;
57         pixmap_x = 0;
58         pixmap_w = 0;
59         pixmap_h = 0;
60         zoom_sample = 0;
61         zoom_track = 0;
62         zoom_y = 0;
63         visible = 1;
65         
66 void ResourcePixmap::resize(int w, int h)
68         int new_w = (w > get_w()) ? w : get_w();
69         int new_h = (h > get_h()) ? h : get_h();
71         BC_Pixmap::resize(new_w, new_h);
75 void ResourcePixmap::draw_data(Edit *edit,
76         int64_t edit_x,
77         int64_t edit_w, 
78         int64_t pixmap_x, 
79         int64_t pixmap_w,
80         int64_t pixmap_h,
81         int mode,
82         int indexes_only)
84 // Get new areas to fill in relative to pixmap
85 // Area to redraw relative to pixmap
86         int refresh_x = 0;
87         int refresh_w = 0;
89 // Ignore if called by resourcethread.
90         if(mode == 3) return;
92         int y = 0;
93         if(mwindow->edl->session->show_titles) y += mwindow->theme->get_image("title_bg_data")->get_h();
94         Track *track = edit->edits->track;
97 // If index can't be drawn, don't do anything.
98         int need_redraw = 0;
99         int64_t index_zoom = 0;
100         if(indexes_only)
101         {
102                 IndexFile indexfile(mwindow);
103                 if(!indexfile.open_index(edit->asset))
104                 {
105                         index_zoom = edit->asset->index_zoom;
106                         indexfile.close_index();
107                 }
109                 if(index_zoom)
110                 {
111                         if(data_type == TRACK_AUDIO)
112                         {
113                                 double asset_over_session = (double)edit->asset->sample_rate / 
114                                         mwindow->edl->session->sample_rate;
115                                         asset_over_session;
116                                 if(index_zoom <= mwindow->edl->local_session->zoom_sample *
117                                         asset_over_session)
118                                         need_redraw = 1;
119                         }
120                 }
122                 if(!need_redraw)
123                         return;
124         }
127 // Redraw everything
128         if(edit->startsource != this->startsource ||
129 /* Incremental drawing is not possible with resource thread */
130                 (data_type == TRACK_AUDIO /* && 
131                         edit->asset->sample_rate != source_samplerate*/ ) ||
132                 (data_type == TRACK_VIDEO /* && 
133                         !EQUIV(edit->asset->frame_rate, source_framerate) */ ) ||
134                 mwindow->edl->session->sample_rate != project_samplerate ||
135                 mwindow->edl->session->frame_rate != project_framerate ||
136                 mwindow->edl->local_session->zoom_sample != zoom_sample || 
137                 mwindow->edl->local_session->zoom_track != zoom_track ||
138                 this->pixmap_h != pixmap_h ||
139                 (data_type == TRACK_AUDIO && 
140                         mwindow->edl->local_session->zoom_y != zoom_y) ||
141                 (mode == 2) ||
142                 need_redraw)
143         {
144 // Shouldn't draw at all if zoomed in below index zoom.
145                 refresh_x = 0;
146                 refresh_w = pixmap_w;
147         }
148         else
149         {
150 // Start translated right
151                 if(pixmap_w == this->pixmap_w && edit_x < this->edit_x && edit_w != pixmap_w)
152                 {
153                         refresh_w = this->edit_x - edit_x;
154                         refresh_x = this->pixmap_w - refresh_w;
156 // Moved completely off the pixmap
157                         if(refresh_w > this->pixmap_w)
158                         {
159                                 refresh_w = this->pixmap_w;
160                                 refresh_x = 0;
161                         }
162                         else
163                         {
164                                 copy_area(refresh_w, 
165                                         y, 
166                                         refresh_x, 
167                                         mwindow->edl->local_session->zoom_track, 
168                                         0, 
169                                         y);
170                         }
171                 }
172                 else
173 // Start translated left
174                 if(pixmap_w == this->pixmap_w && edit_x > this->edit_x && edit_w != pixmap_w)
175                 {
176                         refresh_x = 0;
177                         refresh_w = edit_x - this->edit_x;
179 // Moved completely off the pixmap
180                         if(refresh_w > this->pixmap_w)
181                         {
182                                 refresh_w = this->pixmap_w;
183                         }
184                         else
185                         {
186                                 copy_area(0, 
187                                         y, 
188                                         this->pixmap_w - refresh_w, 
189                                         mwindow->edl->local_session->zoom_track, 
190                                         refresh_w, 
191                                         y);
192                         }
193                 }
194                 else
195 // Start translated right and pixmap came off of right side
196                 if(pixmap_w < this->pixmap_w && edit_x < this->edit_x && 
197                         this->edit_x + edit_w > this->pixmap_x + this->pixmap_w)
198                 {
199                         refresh_w = (this->edit_x + edit_w) - (this->pixmap_x + this->pixmap_w);
200                         refresh_x = pixmap_w - refresh_w;
201                         
202                         if(refresh_w >= pixmap_w)
203                         {
204                                 refresh_x = 0;
205                                 refresh_w = pixmap_w;
206                         }
207                         else
208                         {
209                                 copy_area(this->edit_x - edit_x, 
210                                         y, 
211                                         pixmap_w - refresh_w, 
212                                         mwindow->edl->local_session->zoom_track, 
213                                         0, 
214                                         y);
215                         }
216                 }
217                 else
218 // Start translated right and reduced in size on the right.
219                 if(pixmap_w < this->pixmap_w && edit_x < this->edit_x)
220                 {
221                         refresh_x = 0;
222                         refresh_w = 0;
224                         copy_area(this->pixmap_w - pixmap_w, 
225                                 y, 
226                                 pixmap_w, 
227                                 mwindow->edl->local_session->zoom_track, 
228                                 0, 
229                                 y);
230                 }
231                 else
232 // Start translated left and pixmap came off left side
233                 if(edit_x >= 0 && this->edit_x < 0)
234                 {
235                         refresh_x = 0;
236                         refresh_w = -this->edit_x;
238                         if(refresh_w > pixmap_w)
239                         {
240                                 refresh_w = pixmap_w;
241                         }
242                         else
243                         {
244                                 copy_area(0, 
245                                                 y, 
246                                                 this->pixmap_w, 
247                                                 mwindow->edl->local_session->zoom_track, 
248                                                 refresh_w, 
249                                                 y);
250                         }
251                 }
252                 else
253 // Start translated left and reduced in size on the right
254                 if(pixmap_w < this->pixmap_w && edit_x > this->edit_x)
255                 {
256                         refresh_x = 0;
257                         refresh_w = 0;
258                 }
259                 else
260 // Start translated right and left went into left side.
261                 if(pixmap_w > this->pixmap_w && edit_x < 0 && this->edit_x > 0)
262                 {
263                         refresh_w = pixmap_w - (edit_x + this->pixmap_w);
264                         refresh_x = pixmap_w - refresh_w;
266 // Moved completely off new pixmap
267                         if(refresh_w > pixmap_w)
268                         {
269                                 refresh_w = pixmap_w;
270                                 refresh_x = 0;
271                         }
272                         else
273                         {
274                                 copy_area(-edit_x, 
275                                         y,
276                                         refresh_x,
277                                         mwindow->edl->local_session->zoom_track,
278                                         0,
279                                         y);
280                         }
281                 }
282                 else
283 // Start translated right and increased in size on the right
284                 if(pixmap_w > this->pixmap_w && edit_x <= this->edit_x)
285                 {
286                         refresh_w = pixmap_w - this->pixmap_w;
287                         refresh_x = pixmap_w - refresh_w;
288                 }
289                 else
290 // Start translated left and increased in size on the right
291                 if(pixmap_w > this->pixmap_w && edit_x > this->edit_x)
292                 {
293                         refresh_x = 0;
294                         refresh_w = edit_x - this->edit_x;
296 // Moved completely off new pixmap
297                         if(refresh_w > this->pixmap_w)
298                         {
299                                 refresh_w = pixmap_w;
300                                 refresh_x = 0;
301                         }
302 // Shift and insert
303                         else
304                         {
305                                 copy_area(0, 
306                                         y,
307                                         this->pixmap_w,
308                                         mwindow->edl->local_session->zoom_track,
309                                         refresh_w,
310                                         y);
311                         }
312                 }
313         }
315 // Update pixmap settings
316         this->edit_id = edit->id;
317         this->startsource = edit->startsource;
318         this->source_framerate = edit->asset->frame_rate;
319         this->source_samplerate = edit->asset->sample_rate;
320         this->project_framerate = edit->edl->session->frame_rate;
321         this->project_samplerate = edit->edl->session->sample_rate;
322         this->edit_x = edit_x;
323         this->pixmap_x = pixmap_x;
324         this->pixmap_w = pixmap_w;
325         this->pixmap_h = pixmap_h;
326         this->zoom_sample = mwindow->edl->local_session->zoom_sample;
327         this->zoom_track = mwindow->edl->local_session->zoom_track;
328         this->zoom_y = mwindow->edl->local_session->zoom_y;
332 // Draw in new background
333         if(refresh_w > 0)
334                 mwindow->theme->draw_resource_bg(canvas,
335                         this, 
336                         edit_x,
337                         edit_w,
338                         pixmap_x,
339                         refresh_x, 
340                         y,
341                         refresh_x + refresh_w,
342                         mwindow->edl->local_session->zoom_track + y);
343 //printf("ResourcePixmap::draw_data 70\n");
346 // Draw media
347         if(track->draw)
348         {
349                 switch(track->data_type)
350                 {
351                         case TRACK_AUDIO:
352                                 draw_audio_resource(edit, refresh_x, refresh_w);
353                                 break;
355                         case TRACK_VIDEO:
356                                 draw_video_resource(edit, 
357                                         edit_x, 
358                                         edit_w, 
359                                         pixmap_x,
360                                         pixmap_w,
361                                         refresh_x, 
362                                         refresh_w,
363                                         mode);
364                                 break;
365                 }
366         }
368 // Draw title
369         if(mwindow->edl->session->show_titles)
370                 draw_title(edit, edit_x, edit_w, pixmap_x, pixmap_w);
373 void ResourcePixmap::draw_title(Edit *edit,
374         int64_t edit_x, 
375         int64_t edit_w, 
376         int64_t pixmap_x, 
377         int64_t pixmap_w)
379 // coords relative to pixmap
380         int64_t total_x = edit_x - pixmap_x, total_w = edit_w;
381         int64_t x = total_x, w = total_w;
382         int left_margin = 10;
384         if(x < 0) 
385         {
386                 w -= -x;
387                 x = 0;
388         }
389         if(w > pixmap_w) w -= w - pixmap_w;
391         canvas->draw_3segmenth(x, 
392                 0, 
393                 w, 
394                 total_x,
395                 total_w,
396                 mwindow->theme->get_image("title_bg_data"),
397                 this);
399         if(total_x > -BC_INFINITY)
400         {
401                 char title[BCTEXTLEN], channel[BCTEXTLEN];
402                 FileSystem fs;
404                 if(edit->user_title[0])
405                         strcpy(title, edit->user_title);
406                 else
407                 {
408                         fs.extract_name(title, edit->asset->path);
410                         sprintf(channel, " #%d", edit->channel + 1);
411                         strcat(title, channel);
412                 }
414                 canvas->set_color(mwindow->theme->title_color);
415                 canvas->set_font(mwindow->theme->title_font);
416 //printf("ResourcePixmap::draw_title 1 %d\n", total_x + 10);
417                 
418 // Justify the text on the left boundary of the edit if it is visible.
419 // Otherwise justify it on the left side of the screen.
420                 int text_x = total_x + left_margin;
421                 text_x = MAX(left_margin, text_x);
422                 canvas->draw_text(text_x, 
423                         canvas->get_text_ascent(MEDIUMFONT_3D) + 2, 
424                         title,
425                         strlen(title),
426                         this);
427         }
431 // Need to draw one more x
432 void ResourcePixmap::draw_audio_resource(Edit *edit, int x, int w)
434         if(w <= 0) return;
435         double asset_over_session = (double)edit->asset->sample_rate / 
436                 mwindow->edl->session->sample_rate;
438 // Develop strategy for drawing
439         switch(edit->asset->index_status)
440         {
441                 case INDEX_NOTTESTED:
442                         return;
443                         break;
444 // Disabled.  All files have an index.
445 //              case INDEX_TOOSMALL:
446 //                      draw_audio_source(edit, x, w);
447 //                      break;
448                 case INDEX_BUILDING:
449                 case INDEX_READY:
450                 {
451                         IndexFile indexfile(mwindow);
452                         if(!indexfile.open_index(edit->asset))
453                         {
454                                 if(edit->asset->index_zoom > 
455                                                 mwindow->edl->local_session->zoom_sample * 
456                                                 asset_over_session)
457                                 {
458                                         draw_audio_source(edit, x, w);
459                                 }
460                                 else
461                                         indexfile.draw_index(this, edit, x, w);
462                                 indexfile.close_index();
463                         }
464                         break;
465                 }
466         }
486 void ResourcePixmap::draw_audio_source(Edit *edit, int x, int w)
488         File *source = mwindow->audio_cache->check_out(edit->asset,
489                 mwindow->edl);
491         if(!source)
492         {
493                 printf(_("ResourcePixmap::draw_audio_source: failed to check out %s for drawing.\n"), edit->asset->path);
494                 return;
495         }
497         w++;
498         double asset_over_session = (double)edit->asset->sample_rate / 
499                 mwindow->edl->session->sample_rate;
500         int source_len = w * mwindow->edl->local_session->zoom_sample;
501         int center_pixel = mwindow->edl->local_session->zoom_track / 2;
502         if(mwindow->edl->session->show_titles) center_pixel += mwindow->theme->get_image("title_bg_data")->get_h();
504 // Single sample zoom
505         if(mwindow->edl->local_session->zoom_sample == 1)
506         {
507                 int64_t source_start = (int64_t)(((pixmap_x - edit_x + x) * 
508                         mwindow->edl->local_session->zoom_sample + edit->startsource) *
509                         asset_over_session);
510                 double oldsample, newsample;
511                 int total_source_samples = (int)((double)(source_len + 1) * 
512                         asset_over_session);
513                 double *buffer = new double[total_source_samples];
515                 source->set_audio_position(source_start, 
516                         edit->asset->sample_rate);
517                 source->set_channel(edit->channel);
518                 canvas->set_color(mwindow->theme->audio_color);
520                 if(!source->read_samples(buffer, 
521                         total_source_samples, 
522                         edit->asset->sample_rate))
523                 {
524                         oldsample = newsample = *buffer;
525                         for(int x1 = x, x2 = x + w, i = 0; 
526                                 x1 < x2; 
527                                 x1++, i++)
528                         {
529                                 oldsample = newsample;
530                                 newsample = buffer[(int)(i * asset_over_session)];
531                                 canvas->draw_line(x1 - 1, 
532                                         (int)(center_pixel - oldsample * mwindow->edl->local_session->zoom_y / 2),
533                                         x1,
534                                         (int)(center_pixel - newsample * mwindow->edl->local_session->zoom_y / 2),
535                                         this);
536                         }
537                 }
539                 delete [] buffer;
540                 canvas->test_timer();
541         }
542         else
543 // Multiple sample zoom
544         {
545                 int first_pixel = 1;
546                 int prev_y1 = -1;
547                 int prev_y2 = -1;
548                 int y1;
549                 int y2;
551                 canvas->set_color(mwindow->theme->audio_color);
552 // Draw each pixel from the cache
553                 while(x < w)
554                 {
555 // Starting sample of pixel relative to asset rate.
556                         int64_t source_start = (int64_t)(((pixmap_x - edit_x + x) * 
557                                 mwindow->edl->local_session->zoom_sample + edit->startsource) *
558                                 asset_over_session);
559                         int64_t source_end = (int64_t)(((pixmap_x - edit_x + x + 1) * 
560                                 mwindow->edl->local_session->zoom_sample + edit->startsource) *
561                                 asset_over_session);
562                         WaveCacheItem *item = mwindow->wave_cache->get_wave(edit->asset->id,
563                                         edit->channel,
564                                         source_start,
565                                         source_end);
566                         if(item)
567                         {
568                                 y1 = (int)(center_pixel - 
569                                         item->low * mwindow->edl->local_session->zoom_y / 2);
570                                 y2 = (int)(center_pixel - 
571                                         item->high * mwindow->edl->local_session->zoom_y / 2);
572                                 if(first_pixel)
573                                 {
574                                         canvas->draw_line(x, 
575                                                 y1,
576                                                 x,
577                                                 y2,
578                                                 this);
579                                         first_pixel = 0;
580                                 }
581                                 else
582                                         canvas->draw_line(x, 
583                                                 MIN(y1, prev_y2),
584                                                 x,
585                                                 MAX(y2, prev_y1),
586                                                 this);
587                                 prev_y1 = y1;
588                                 prev_y2 = y2;
589                                 first_pixel = 0;
590                                 mwindow->wave_cache->unlock();
591                         }
592                         else
593                         {
594                                 first_pixel = 1;
595                                 canvas->resource_thread->add_wave(this,
596                                         edit->asset,
597                                         x,
598                                         edit->channel,
599                                         source_start,
600                                         source_end);
601                         }
603                         x++;
604                 }
605         }
607         mwindow->audio_cache->check_in(edit->asset);
612 void ResourcePixmap::draw_wave(int x, double high, double low)
614         int top_pixel = 0;
615         if(mwindow->edl->session->show_titles) 
616                 top_pixel = mwindow->theme->get_image("title_bg_data")->get_h();
617         int center_pixel = mwindow->edl->local_session->zoom_track / 2 + top_pixel;
618         int bottom_pixel = top_pixel + mwindow->edl->local_session->zoom_track;
619         int y1 = (int)(center_pixel - 
620                 low * mwindow->edl->local_session->zoom_y / 2);
621         int y2 = (int)(center_pixel - 
622                 high * mwindow->edl->local_session->zoom_y / 2);
623         CLAMP(y1, top_pixel, bottom_pixel);
624         CLAMP(y2, top_pixel, bottom_pixel);
625         canvas->set_color(mwindow->theme->audio_color);
626         canvas->draw_line(x, 
627                 y1,
628                 x,
629                 y2,
630                 this);
652 void ResourcePixmap::draw_video_resource(Edit *edit, 
653         int64_t edit_x, 
654         int64_t edit_w, 
655         int64_t pixmap_x,
656         int64_t pixmap_w,
657         int refresh_x, 
658         int refresh_w,
659         int mode)
661 // pixels spanned by a picon
662         int64_t picon_w = Units::round(edit->picon_w());
663         int64_t picon_h = edit->picon_h();
666 // Don't draw video if picon is bigger than edit
667         if(picon_w > edit_w) return;
669 // pixels spanned by a frame
670         double frame_w = edit->frame_w();
672 // Frames spanned by a picon
673         double frames_per_picon = edit->frames_per_picon();
675 // Current pixel relative to pixmap
676         int x = 0;
677         int y = 0;
678         if(mwindow->edl->session->show_titles) 
679                 y += mwindow->theme->get_image("title_bg_data")->get_h();
680 // Frame in project touched by current pixel
681         int64_t project_frame;
683 // Get first frame touched by x and fix x to start of frame
684         if(frames_per_picon > 1)
685         {
686                 int picon = Units::to_int64(
687                         (double)((int64_t)refresh_x + pixmap_x - edit_x) / 
688                         picon_w);
689                 x = picon_w * picon + edit_x - pixmap_x;
690                 project_frame = Units::to_int64((double)picon * frames_per_picon);
691         }
692         else
693         {
694                 project_frame = Units::to_int64((double)((int64_t)refresh_x + pixmap_x - edit_x) / 
695                         frame_w);
696                 x = Units::round((double)project_frame * frame_w + edit_x - pixmap_x);
697         }
700 // Draw only cached frames
701         while(x < refresh_x + refresh_w)
702         {
703                 int64_t source_frame = project_frame + edit->startsource;
704                 VFrame *picon_frame = 0;
705                 int use_cache = 0;
707                 if((picon_frame = mwindow->frame_cache->get_frame_ptr(source_frame,
708                         edit->channel,
709                         mwindow->edl->session->frame_rate,
710                         BC_RGB888,
711                         picon_w,
712                         picon_h,
713                         edit->asset->id)) != 0)
714                 {
715                         use_cache = 1;
716                 }
717                 else
718                 {
719 // Set picon thread to display from file
720                         if(mode != 3)
721                         {
723                                 canvas->resource_thread->add_picon(this, 
724                                         x, 
725                                         y, 
726                                         picon_w,
727                                         picon_h,
728                                         mwindow->edl->session->frame_rate,
729                                         source_frame,
730                                         edit->channel,
731                                         edit->asset);
732                         }
733                 }
735                 if(picon_frame)
736                         draw_vframe(picon_frame, 
737                                 x, 
738                                 y, 
739                                 picon_w, 
740                                 picon_h, 
741                                 0, 
742                                 0);
745 // Unlock the get_frame_ptr command
746                 if(use_cache)
747                         mwindow->frame_cache->unlock();
748                 
749                 if(frames_per_picon > 1)
750                 {
751                         x += Units::round(picon_w);
752                         project_frame = Units::to_int64(frames_per_picon * (int64_t)((double)(x + pixmap_x - edit_x) / picon_w));
753                 }
754                 else
755                 {
756                         x += Units::round(frame_w);
757                         project_frame = (int64_t)((double)(x + pixmap_x - edit_x) / frame_w);
758                 }
761                 canvas->test_timer();
762         }
766 void ResourcePixmap::dump()
768         printf("ResourcePixmap %p\n", this);
769         printf(" edit %x edit_x %d pixmap_x %d pixmap_w %d visible %d\n", edit_id, edit_x, pixmap_x, pixmap_w, visible);
775 //      Local Variables:
776 //      mode: C++
777 //      c-file-style: "linux"
778 //      End: