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
28 #include "bcsignals.h"
31 #include "bccmodels.h"
36 #include "edlsession.h"
38 #include "filesystem.h"
39 #include "framecache.h"
40 #include "indexfile.h"
42 #include "localsession.h"
44 #include "mwindowgui.h"
45 #include "renderengine.h"
46 #include "resourcethread.h"
47 #include "resourcepixmap.h"
50 #include "timelinepane.h"
52 #include "trackcanvas.h"
53 #include "transportque.h"
56 #include "wavecache.h"
59 ResourcePixmap::ResourcePixmap(MWindow *mwindow,
65 : BC_Pixmap(gui, w, h)
69 this->mwindow = mwindow;
71 this->pane_number = pane_number;
72 startsource = edit->startsource;
73 data_type = edit->track->data_type;
76 source_framerate = edit->asset->frame_rate;
77 source_samplerate = edit->asset->sample_rate;
82 source_framerate = edit->nested_edl->session->frame_rate;
83 source_samplerate = edit->nested_edl->session->sample_rate;
86 project_framerate = edit->edl->session->frame_rate;
87 project_samplerate = edit->edl->session->sample_rate;
88 edit_id = edit->id; pixmap_w = w; pixmap_h = h;
91 ResourcePixmap::~ResourcePixmap()
96 void ResourcePixmap::reset()
108 void ResourcePixmap::resize(int w, int h)
110 int new_w = (w > get_w()) ? w : get_w();
111 int new_h = (h > get_h()) ? h : get_h();
113 BC_Pixmap::resize(new_w, new_h);
117 void ResourcePixmap::draw_data(TrackCanvas *canvas,
127 // Get new areas to fill in relative to pixmap
128 // Area to redraw relative to pixmap
132 // Ignore if called by resourcethread.
133 // if(mode == IGNORE_THREAD) return;
136 if(mwindow->edl->session->show_titles)
137 y += mwindow->theme->get_image("title_bg_data")->get_h();
138 Track *track = edit->edits->track;
141 // If want indexes only & index can't be drawn, don't do anything.
143 int64_t index_zoom = 0;
144 Indexable *indexable = 0;
145 if(edit->asset) indexable = edit->asset;
146 if(edit->nested_edl) indexable = edit->nested_edl;
147 if(indexable && indexes_only)
149 IndexFile indexfile(mwindow, indexable);
150 if(!indexfile.open_index())
152 index_zoom = indexable->index_state->index_zoom;
153 indexfile.close_index();
158 if(data_type == TRACK_AUDIO)
160 double asset_over_session = (double)indexable->get_sample_rate() /
161 mwindow->edl->session->sample_rate;
162 if(index_zoom <= mwindow->edl->local_session->zoom_sample *
174 /* Incremental drawing is not possible with resource thread */
176 // edit->startsource != this->startsource ||
177 // mwindow->edl->session->sample_rate != project_samplerate ||
178 // !EQUIV(mwindow->edl->session->frame_rate, project_framerate) ||
179 // mwindow->edl->local_session->zoom_sample != zoom_sample ||
180 // mwindow->edl->local_session->zoom_track != zoom_track ||
181 // this->pixmap_h != pixmap_h ||
182 // (data_type == TRACK_AUDIO &&
183 // mwindow->edl->local_session->zoom_y != zoom_y) ||
187 // Redraw the whole thing.
189 refresh_w = pixmap_w;
193 // Start translated right
194 if(pixmap_w == this->pixmap_w && edit_x < this->edit_x && edit_w != pixmap_w)
196 refresh_w = this->edit_x - edit_x;
197 refresh_x = this->pixmap_w - refresh_w;
199 // Moved completely off the pixmap
200 if(refresh_w > this->pixmap_w)
202 refresh_w = this->pixmap_w;
210 mwindow->edl->local_session->zoom_track,
216 // Start translated left
217 if(pixmap_w == this->pixmap_w && edit_x > this->edit_x && edit_w != pixmap_w)
220 refresh_w = edit_x - this->edit_x;
222 // Moved completely off the pixmap
223 if(refresh_w > this->pixmap_w)
225 refresh_w = this->pixmap_w;
231 this->pixmap_w - refresh_w,
232 mwindow->edl->local_session->zoom_track,
238 // Start translated right and pixmap came off of right side
239 if(pixmap_w < this->pixmap_w && edit_x < this->edit_x &&
240 this->edit_x + edit_w > this->pixmap_x + this->pixmap_w)
242 refresh_w = (this->edit_x + edit_w) - (this->pixmap_x + this->pixmap_w);
243 refresh_x = pixmap_w - refresh_w;
245 if(refresh_w >= pixmap_w)
248 refresh_w = pixmap_w;
252 copy_area(this->edit_x - edit_x,
254 pixmap_w - refresh_w,
255 mwindow->edl->local_session->zoom_track,
261 // Start translated right and reduced in size on the right.
262 if(pixmap_w < this->pixmap_w && edit_x < this->edit_x)
267 copy_area(this->pixmap_w - pixmap_w,
270 mwindow->edl->local_session->zoom_track,
275 // Start translated left and pixmap came off left side
276 if(edit_x >= 0 && this->edit_x < 0)
279 refresh_w = -this->edit_x;
281 if(refresh_w > pixmap_w)
283 refresh_w = pixmap_w;
290 mwindow->edl->local_session->zoom_track,
296 // Start translated left and reduced in size on the right
297 if(pixmap_w < this->pixmap_w && edit_x > this->edit_x)
303 // Start translated right and left went into left side.
304 if(pixmap_w > this->pixmap_w && edit_x < 0 && this->edit_x > 0)
306 refresh_w = pixmap_w - (edit_x + this->pixmap_w);
307 refresh_x = pixmap_w - refresh_w;
309 // Moved completely off new pixmap
310 if(refresh_w > pixmap_w)
312 refresh_w = pixmap_w;
320 mwindow->edl->local_session->zoom_track,
326 // Start translated right and increased in size on the right
327 if(pixmap_w > this->pixmap_w && edit_x <= this->edit_x)
329 refresh_w = pixmap_w - this->pixmap_w;
330 refresh_x = pixmap_w - refresh_w;
333 // Start translated left and increased in size on the right
334 if(pixmap_w > this->pixmap_w && edit_x > this->edit_x)
337 refresh_w = edit_x - this->edit_x;
339 // Moved completely off new pixmap
340 if(refresh_w > this->pixmap_w)
342 refresh_w = pixmap_w;
351 mwindow->edl->local_session->zoom_track,
358 // Update pixmap settings
359 this->edit_id = edit->id;
360 this->startsource = edit->startsource;
363 this->source_framerate = edit->asset->frame_rate;
366 this->source_framerate = edit->nested_edl->session->frame_rate;
369 this->source_samplerate = edit->asset->sample_rate;
372 this->source_samplerate = edit->nested_edl->session->sample_rate;
374 this->project_framerate = edit->edl->session->frame_rate;
375 this->project_samplerate = edit->edl->session->sample_rate;
376 this->edit_x = edit_x;
377 this->pixmap_x = pixmap_x;
378 this->pixmap_w = pixmap_w;
379 this->pixmap_h = pixmap_h;
380 this->zoom_sample = mwindow->edl->local_session->zoom_sample;
381 this->zoom_track = mwindow->edl->local_session->zoom_track;
382 this->zoom_y = mwindow->edl->local_session->zoom_y;
386 // Draw background image
388 mwindow->theme->draw_resource_bg(canvas,
395 refresh_x + refresh_w,
396 mwindow->edl->local_session->zoom_track + y);
397 //printf("ResourcePixmap::draw_data 70\n");
400 // Draw media which already exists
403 switch(track->data_type)
406 draw_audio_resource(canvas,
413 draw_video_resource(canvas,
425 draw_subttl_resource(canvas,
435 if(mwindow->edl->session->show_titles)
445 void ResourcePixmap::draw_title(TrackCanvas *canvas,
452 // coords relative to pixmap
453 int64_t total_x = edit_x - pixmap_x, total_w = edit_w;
454 int64_t x = total_x, w = total_w;
455 int left_margin = 10;
462 if(w > pixmap_w) w -= w - pixmap_w;
464 canvas->draw_3segmenth(x,
469 mwindow->theme->get_image("title_bg_data"),
472 // if(total_x > -BC_INFINITY)
474 char title[BCTEXTLEN];
475 char channel[BCTEXTLEN];
480 if(edit->user_title[0])
481 strcpy(title, edit->user_title);
485 //printf("ResourcePixmap::draw_title %s\n", edit->nested_edl->project_path);
486 fs.extract_name(title, edit->nested_edl->path);
488 // EDLs only have 1 video output
489 if(edit->track->data_type == TRACK_AUDIO)
491 sprintf(channel, " #%d", edit->channel + 1);
492 strcat(title, channel);
498 fs.extract_name(title, edit->asset->path);
499 sprintf(channel, " #%d", edit->channel + 1);
500 strcat(title, channel);
503 canvas->set_color(mwindow->theme->title_color);
504 canvas->set_font(mwindow->theme->title_font);
506 // Justify the text on the left boundary of the edit if it is visible.
507 // Otherwise justify it on the left side of the screen.
508 int text_x = total_x + left_margin;
509 text_x = MAX(left_margin, text_x);
510 //printf("ResourcePixmap::draw_title 1 %d\n", text_x);
511 canvas->draw_text(text_x,
512 canvas->get_text_ascent(mwindow->theme->title_font) + 2,
520 // Need to draw one more x
521 void ResourcePixmap::draw_audio_resource(TrackCanvas *canvas,
527 if(!edit->asset && !edit->nested_edl) return;
528 Indexable *indexable = 0;
529 if(edit->asset) indexable = edit->asset;
530 if(edit->nested_edl) indexable = edit->nested_edl;
531 // printf("ResourcePixmap::draw_audio_resource %d x=%d w=%d\n",
537 IndexState *index_state = indexable->index_state;
538 double asset_over_session = (double)indexable->get_sample_rate() /
539 mwindow->edl->session->sample_rate;
541 // Develop strategy for drawing
542 // printf("ResourcePixmap::draw_audio_resource %d %p %d\n",
545 // index_state->index_status);
546 switch(index_state->index_status)
548 case INDEX_NOTTESTED:
551 // Disabled. All files have an index.
552 // case INDEX_TOOSMALL:
553 // draw_audio_source(canvas, edit, x, w);
558 IndexFile indexfile(mwindow, indexable);
559 if(!indexfile.open_index())
561 if(index_state->index_zoom >
562 mwindow->edl->local_session->zoom_sample *
565 //printf("ResourcePixmap::draw_audio_resource %d\n", __LINE__);
567 draw_audio_source(canvas, edit, x, w);
571 //printf("ResourcePixmap::draw_audio_resource %d\n", __LINE__);
572 indexfile.draw_index(canvas,
580 indexfile.close_index();
605 void ResourcePixmap::draw_audio_source(TrackCanvas *canvas,
611 Indexable *indexable = edit->get_source();
612 double asset_over_session = (double)indexable->get_sample_rate() /
613 mwindow->edl->session->sample_rate;
614 int source_len = w * mwindow->edl->local_session->zoom_sample;
615 int center_pixel = mwindow->edl->local_session->zoom_track / 2;
616 if(mwindow->edl->session->show_titles)
617 center_pixel += mwindow->theme->get_image("title_bg_data")->get_h();
619 int64_t scale_y = mwindow->edl->local_session->zoom_y;
620 int y_max = center_pixel + scale_y / 2 - 1;
621 // Single sample zoom
622 if(mwindow->edl->local_session->zoom_sample == 1)
624 int64_t source_start = (int64_t)(((pixmap_x - edit_x + x) *
625 mwindow->edl->local_session->zoom_sample + edit->startsource) *
627 int total_source_samples = (int)((double)(source_len + 1) *
629 Samples *buffer = new Samples(total_source_samples);
631 canvas->set_color(mwindow->theme->audio_color);
633 if(indexable->is_asset)
635 mwindow->gui->unlock_window();
636 File *source = mwindow->audio_cache->check_out(edit->asset, mwindow->edl);
637 mwindow->gui->lock_window("draw_audio_source");
641 printf(_("ResourcePixmap::draw_audio_source: failed to check out %s for drawing.\n"), edit->asset->path);
646 source->set_audio_position(source_start);
647 source->set_channel(edit->channel);
648 result = source->read_samples(buffer, total_source_samples);
649 mwindow->audio_cache->check_in(edit->asset);
653 if(mwindow->gui->render_engine &&
654 mwindow->gui->render_engine_id != indexable->id)
656 delete mwindow->gui->render_engine;
657 mwindow->gui->render_engine = 0;
660 if(!mwindow->gui->render_engine)
662 TransportCommand command;
663 command.command = NORMAL_FWD;
664 command.get_edl()->copy_all(edit->nested_edl);
665 command.change_type = CHANGE_ALL;
666 command.realtime = 0;
667 mwindow->gui->render_engine = new RenderEngine(0,
668 mwindow->preferences, 0, 0);
669 mwindow->gui->render_engine_id = edit->nested_edl->id;
670 mwindow->gui->render_engine->set_acache(mwindow->audio_cache);
671 mwindow->gui->render_engine->arm_command(&command);
674 Samples *temp_buffer[MAX_CHANNELS];
675 bzero(temp_buffer, MAX_CHANNELS * sizeof(double*));
676 for(int i = 0; i < indexable->get_audio_channels(); i++)
678 temp_buffer[i] = new Samples(total_source_samples);
681 if(mwindow->gui->render_engine->arender)
683 mwindow->gui->render_engine->arender->process_buffer(
685 total_source_samples,
687 memcpy(buffer->get_data(),
688 temp_buffer[edit->channel]->get_data(),
689 total_source_samples * sizeof(double));
692 for(int i = 0; i < indexable->get_audio_channels(); i++)
694 delete temp_buffer[i];
703 double *samples = buffer->get_data();
704 int x2 = x, y = (int)(center_pixel - samples[0] * scale_y / 2);
705 int y2 = CLIP(y,0,y_max);
707 for(int i=1, x_max=x+w-1; x2<x_max; i++)
709 int x1 = x2, y1 = y2; ++x2;
710 int j = (int)(i * asset_over_session);
711 y = (int)(center_pixel - samples[j] * scale_y / 2);
712 y2 = CLIP(y, 0, y_max);
714 //printf("ResourcePixmap::draw_audio_source %d %d %d\n", __LINE__, y1, y2);
715 canvas->draw_line(x1, y1, x2, y2, this);
722 // Multiple sample zoom
729 canvas->set_color(mwindow->theme->audio_color);
730 // Draw each pixel from the cache
731 //printf("ResourcePixmap::draw_audio_source %d x=%d w=%d\n", __LINE__, x, w);
734 // Starting sample of pixel relative to asset rate.
735 int64_t source_start = (int64_t)(((pixmap_x - edit_x + x) *
736 mwindow->edl->local_session->zoom_sample + edit->startsource) *
738 int64_t source_end = (int64_t)(((pixmap_x - edit_x + x + 1) *
739 mwindow->edl->local_session->zoom_sample + edit->startsource) *
741 WaveCacheItem *item = mwindow->wave_cache->get_wave(indexable->id,
747 //printf("ResourcePixmap::draw_audio_source %d\n", __LINE__);
748 int y_lo = (int)(center_pixel - item->low * scale_y / 2);
749 int y1 = CLIP(y_lo, 0, y_max);
750 int y_hi = (int)(center_pixel - item->high * scale_y / 2);
751 int y2 = CLIP(y_hi, 0, y_max);
755 y_lo = MIN(y1,prev_y2);
756 y_hi = MAX(y2,prev_y1);
764 prev_y1 = y1; prev_y2 = y2;
765 canvas->draw_line(x, y_lo, x, y_hi, this);
767 //printf("ResourcePixmap::draw_audio_source %d %d %d %d\n", __LINE__, x, y1, y2);
769 mwindow->wave_cache->unlock();
773 //printf("ResourcePixmap::draw_audio_source %d\n", __LINE__);
775 gui->resource_thread->add_wave(this,
776 canvas->pane->number,
787 canvas->test_timer();
792 void ResourcePixmap::draw_wave(TrackCanvas *canvas,
798 if(mwindow->edl->session->show_titles)
799 top_pixel = mwindow->theme->get_image("title_bg_data")->get_h();
800 int center_pixel = mwindow->edl->local_session->zoom_track / 2 + top_pixel;
801 int bottom_pixel = top_pixel + mwindow->edl->local_session->zoom_track;
802 int y1 = (int)(center_pixel -
803 low * mwindow->edl->local_session->zoom_y / 2);
804 int y2 = (int)(center_pixel -
805 high * mwindow->edl->local_session->zoom_y / 2);
806 CLAMP(y1, top_pixel, bottom_pixel);
807 CLAMP(y2, top_pixel, bottom_pixel);
808 canvas->set_color(mwindow->theme->audio_color);
835 void ResourcePixmap::draw_video_resource(TrackCanvas *canvas,
846 //BC_Signals::dump_stack();
848 // pixels spanned by a picon
849 int64_t picon_w = Units::round(edit->picon_w());
850 int64_t picon_h = edit->picon_h();
853 // if( picon_w <= 0 || picon_w > edit_w ) return;
854 // Don't draw video if picon is empty, or edit only hairline
855 if( picon_w < 1 || edit_w < 2 ) return;
856 // or bigger than edit and fills at less than 1.5 percent timeline
857 if( picon_w > edit_w && edit_w < canvas->get_w()/64 ) return;
859 // pixels spanned by a frame
860 double frame_w = edit->frame_w();
862 // Frames spanned by a picon
863 double frames_per_picon = edit->frames_per_picon();
865 // Current pixel relative to pixmap
868 if(mwindow->edl->session->show_titles)
869 y += mwindow->theme->get_image("title_bg_data")->get_h();
870 // Frame in project touched by current pixel
871 int64_t project_frame;
873 // Get first frame touched by x and fix x to start of frame
874 if(frames_per_picon > 1)
876 int picon = Units::to_int64(
877 (double)((int64_t)refresh_x + pixmap_x - edit_x) /
879 x = picon_w * picon + edit_x - pixmap_x;
880 project_frame = Units::to_int64((double)picon * frames_per_picon);
884 project_frame = Units::to_int64((double)((int64_t)refresh_x + pixmap_x - edit_x) /
886 x = Units::round((double)project_frame * frame_w + edit_x - pixmap_x);
890 // Draw only cached frames
891 while(x < refresh_x + refresh_w)
893 int64_t source_frame = project_frame + edit->startsource;
894 VFrame *picon_frame = 0;
895 Indexable *indexable = edit->get_source();
903 picon_frame = mwindow->frame_cache->get_frame_ptr(source_frame,
905 mwindow->edl->session->frame_rate,
918 // Set picon thread to draw in background
919 if(mode != IGNORE_THREAD)
921 // printf("ResourcePixmap::draw_video_resource %d %d %lld\n",
923 // mwindow->frame_cache->total(),
925 gui->resource_thread->add_picon(this,
926 canvas->pane->number,
931 mwindow->edl->session->frame_rate,
939 draw_vframe(picon_frame,
948 // Unlock the get_frame_ptr command
950 mwindow->frame_cache->unlock();
952 if(frames_per_picon > 1)
954 x += Units::round(picon_w);
955 project_frame = Units::to_int64(frames_per_picon * (int64_t)((double)(x + pixmap_x - edit_x) / picon_w));
959 x += Units::round(frame_w);
960 project_frame = (int64_t)((double)(x + pixmap_x - edit_x) / frame_w);
964 canvas->test_timer();
970 void ResourcePixmap::draw_subttl_resource(TrackCanvas *canvas,
975 SEdit *sedit = (SEdit *)edit;
976 char *text = sedit->get_text();
977 if( !*text || w < 10 ) return;
978 int center_pixel = mwindow->edl->local_session->zoom_track / 2;
979 if(mwindow->edl->session->show_titles)
980 center_pixel += mwindow->theme->get_image("title_bg_data")->get_h();
981 int64_t scale_y = mwindow->edl->local_session->zoom_y;
983 if( x0 < 0 ) x0 = -x0;
984 int x1 = (int)(pixmap_x - x0 + x);
985 int y_max = center_pixel + scale_y / 2 - 1;
986 int font = MEDIUMFONT, color = WHITE;
987 canvas->set_font(font);
988 canvas->set_color(color);
989 int ch = canvas->get_text_height(font);
990 int hh = canvas->get_text_height(font,text) + ch/2;
991 int y1 = y_max - hh - 10;
993 canvas->draw_text(x1, y1, text, -1, this);
996 void ResourcePixmap::dump()
998 printf("ResourcePixmap %p\n", this);
999 printf(" edit %jx edit_x %jd pixmap_x %jd pixmap_w %jd visible %d\n",
1000 edit_id, edit_x, pixmap_x, pixmap_w, visible);