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 "colormodels.h"
36 #include "edlsession.h"
38 #include "filesystem.h"
40 #include "framecache.h"
41 #include "indexfile.h"
43 #include "localsession.h"
45 #include "mwindowgui.h"
46 #include "renderengine.h"
47 #include "resourcethread.h"
48 #include "resourcepixmap.h"
51 #include "timelinepane.h"
53 #include "trackcanvas.h"
54 #include "transportque.h"
57 #include "wavecache.h"
60 ResourcePixmap::ResourcePixmap(MWindow *mwindow,
66 : BC_Pixmap(gui, w, h)
70 this->mwindow = mwindow;
72 this->pane_number = pane_number;
73 startsource = edit->startsource;
74 data_type = edit->track->data_type;
77 source_framerate = edit->asset->frame_rate;
78 source_samplerate = edit->asset->sample_rate;
83 source_framerate = edit->nested_edl->session->frame_rate;
84 source_samplerate = edit->nested_edl->session->sample_rate;
87 project_framerate = edit->edl->session->frame_rate;
88 project_samplerate = edit->edl->session->sample_rate;
89 edit_id = edit->id; pixmap_w = w; pixmap_h = h;
92 ResourcePixmap::~ResourcePixmap()
97 void ResourcePixmap::reset()
109 void ResourcePixmap::resize(int w, int h)
111 int new_w = (w > get_w()) ? w : get_w();
112 int new_h = (h > get_h()) ? h : get_h();
114 BC_Pixmap::resize(new_w, new_h);
118 void ResourcePixmap::draw_data(TrackCanvas *canvas,
128 // Get new areas to fill in relative to pixmap
129 // Area to redraw relative to pixmap
133 // Ignore if called by resourcethread.
134 // if(mode == IGNORE_THREAD) return;
137 if(mwindow->edl->session->show_titles)
138 y += mwindow->theme->get_image("title_bg_data")->get_h();
139 Track *track = edit->edits->track;
142 // If want indexes only & index can't be drawn, don't do anything.
144 int64_t index_zoom = 0;
145 Indexable *indexable = 0;
146 if(edit->asset) indexable = edit->asset;
147 if(edit->nested_edl) indexable = edit->nested_edl;
148 if(indexable && indexes_only)
150 IndexFile indexfile(mwindow, indexable);
151 if(!indexfile.open_index())
153 index_zoom = indexable->index_state->index_zoom;
154 indexfile.close_index();
159 if(data_type == TRACK_AUDIO)
161 double asset_over_session = (double)indexable->get_sample_rate() /
162 mwindow->edl->session->sample_rate;
163 if(index_zoom <= mwindow->edl->local_session->zoom_sample *
175 /* Incremental drawing is not possible with resource thread */
177 // edit->startsource != this->startsource ||
178 // mwindow->edl->session->sample_rate != project_samplerate ||
179 // !EQUIV(mwindow->edl->session->frame_rate, project_framerate) ||
180 // mwindow->edl->local_session->zoom_sample != zoom_sample ||
181 // mwindow->edl->local_session->zoom_track != zoom_track ||
182 // this->pixmap_h != pixmap_h ||
183 // (data_type == TRACK_AUDIO &&
184 // mwindow->edl->local_session->zoom_y != zoom_y) ||
188 // Redraw the whole thing.
190 refresh_w = pixmap_w;
194 // Start translated right
195 if(pixmap_w == this->pixmap_w && edit_x < this->edit_x && edit_w != pixmap_w)
197 refresh_w = this->edit_x - edit_x;
198 refresh_x = this->pixmap_w - refresh_w;
200 // Moved completely off the pixmap
201 if(refresh_w > this->pixmap_w)
203 refresh_w = this->pixmap_w;
211 mwindow->edl->local_session->zoom_track,
217 // Start translated left
218 if(pixmap_w == this->pixmap_w && edit_x > this->edit_x && edit_w != pixmap_w)
221 refresh_w = edit_x - this->edit_x;
223 // Moved completely off the pixmap
224 if(refresh_w > this->pixmap_w)
226 refresh_w = this->pixmap_w;
232 this->pixmap_w - refresh_w,
233 mwindow->edl->local_session->zoom_track,
239 // Start translated right and pixmap came off of right side
240 if(pixmap_w < this->pixmap_w && edit_x < this->edit_x &&
241 this->edit_x + edit_w > this->pixmap_x + this->pixmap_w)
243 refresh_w = (this->edit_x + edit_w) - (this->pixmap_x + this->pixmap_w);
244 refresh_x = pixmap_w - refresh_w;
246 if(refresh_w >= pixmap_w)
249 refresh_w = pixmap_w;
253 copy_area(this->edit_x - edit_x,
255 pixmap_w - refresh_w,
256 mwindow->edl->local_session->zoom_track,
262 // Start translated right and reduced in size on the right.
263 if(pixmap_w < this->pixmap_w && edit_x < this->edit_x)
268 copy_area(this->pixmap_w - pixmap_w,
271 mwindow->edl->local_session->zoom_track,
276 // Start translated left and pixmap came off left side
277 if(edit_x >= 0 && this->edit_x < 0)
280 refresh_w = -this->edit_x;
282 if(refresh_w > pixmap_w)
284 refresh_w = pixmap_w;
291 mwindow->edl->local_session->zoom_track,
297 // Start translated left and reduced in size on the right
298 if(pixmap_w < this->pixmap_w && edit_x > this->edit_x)
304 // Start translated right and left went into left side.
305 if(pixmap_w > this->pixmap_w && edit_x < 0 && this->edit_x > 0)
307 refresh_w = pixmap_w - (edit_x + this->pixmap_w);
308 refresh_x = pixmap_w - refresh_w;
310 // Moved completely off new pixmap
311 if(refresh_w > pixmap_w)
313 refresh_w = pixmap_w;
321 mwindow->edl->local_session->zoom_track,
327 // Start translated right and increased in size on the right
328 if(pixmap_w > this->pixmap_w && edit_x <= this->edit_x)
330 refresh_w = pixmap_w - this->pixmap_w;
331 refresh_x = pixmap_w - refresh_w;
334 // Start translated left and increased in size on the right
335 if(pixmap_w > this->pixmap_w && edit_x > this->edit_x)
338 refresh_w = edit_x - this->edit_x;
340 // Moved completely off new pixmap
341 if(refresh_w > this->pixmap_w)
343 refresh_w = pixmap_w;
352 mwindow->edl->local_session->zoom_track,
359 // Update pixmap settings
360 this->edit_id = edit->id;
361 this->startsource = edit->startsource;
364 this->source_framerate = edit->asset->frame_rate;
367 this->source_framerate = edit->nested_edl->session->frame_rate;
370 this->source_samplerate = edit->asset->sample_rate;
373 this->source_samplerate = edit->nested_edl->session->sample_rate;
375 this->project_framerate = edit->edl->session->frame_rate;
376 this->project_samplerate = edit->edl->session->sample_rate;
377 this->edit_x = edit_x;
378 this->pixmap_x = pixmap_x;
379 this->pixmap_w = pixmap_w;
380 this->pixmap_h = pixmap_h;
381 this->zoom_sample = mwindow->edl->local_session->zoom_sample;
382 this->zoom_track = mwindow->edl->local_session->zoom_track;
383 this->zoom_y = mwindow->edl->local_session->zoom_y;
387 // Draw background image
389 mwindow->theme->draw_resource_bg(canvas,
396 refresh_x + refresh_w,
397 mwindow->edl->local_session->zoom_track + y);
398 //printf("ResourcePixmap::draw_data 70\n");
401 // Draw media which already exists
404 switch(track->data_type)
407 draw_audio_resource(canvas,
414 draw_video_resource(canvas,
426 draw_subttl_resource(canvas,
436 if(mwindow->edl->session->show_titles)
446 void ResourcePixmap::draw_title(TrackCanvas *canvas,
453 // coords relative to pixmap
454 int64_t total_x = edit_x - pixmap_x, total_w = edit_w;
455 int64_t x = total_x, w = total_w;
456 int left_margin = 10;
463 if(w > pixmap_w) w -= w - pixmap_w;
465 canvas->draw_3segmenth(x,
470 mwindow->theme->get_image("title_bg_data"),
473 // if(total_x > -BC_INFINITY)
475 char title[BCTEXTLEN];
476 char channel[BCTEXTLEN];
481 if(edit->user_title[0])
482 strcpy(title, edit->user_title);
486 //printf("ResourcePixmap::draw_title %s\n", edit->nested_edl->project_path);
487 fs.extract_name(title, edit->nested_edl->path);
489 // EDLs only have 1 video output
490 if(edit->track->data_type == TRACK_AUDIO)
492 sprintf(channel, " #%d", edit->channel + 1);
493 strcat(title, channel);
499 fs.extract_name(title, edit->asset->path);
500 sprintf(channel, " #%d", edit->channel + 1);
501 strcat(title, channel);
504 canvas->set_color(mwindow->theme->title_color);
505 canvas->set_font(mwindow->theme->title_font);
507 // Justify the text on the left boundary of the edit if it is visible.
508 // Otherwise justify it on the left side of the screen.
509 int text_x = total_x + left_margin;
510 text_x = MAX(left_margin, text_x);
511 //printf("ResourcePixmap::draw_title 1 %d\n", text_x);
512 canvas->draw_text(text_x,
513 canvas->get_text_ascent(mwindow->theme->title_font) + 2,
521 // Need to draw one more x
522 void ResourcePixmap::draw_audio_resource(TrackCanvas *canvas,
528 if(!edit->asset && !edit->nested_edl) return;
529 Indexable *indexable = 0;
530 if(edit->asset) indexable = edit->asset;
531 if(edit->nested_edl) indexable = edit->nested_edl;
532 // printf("ResourcePixmap::draw_audio_resource %d x=%d w=%d\n",
538 IndexState *index_state = indexable->index_state;
539 double asset_over_session = (double)indexable->get_sample_rate() /
540 mwindow->edl->session->sample_rate;
542 // Develop strategy for drawing
543 // printf("ResourcePixmap::draw_audio_resource %d %p %d\n",
546 // index_state->index_status);
547 switch(index_state->index_status)
549 case INDEX_NOTTESTED:
552 // Disabled. All files have an index.
553 // case INDEX_TOOSMALL:
554 // draw_audio_source(canvas, edit, x, w);
559 IndexFile indexfile(mwindow, indexable);
560 if(!indexfile.open_index())
562 if(index_state->index_zoom >
563 mwindow->edl->local_session->zoom_sample *
566 //printf("ResourcePixmap::draw_audio_resource %d\n", __LINE__);
568 draw_audio_source(canvas, edit, x, w);
572 //printf("ResourcePixmap::draw_audio_resource %d\n", __LINE__);
573 indexfile.draw_index(canvas,
581 indexfile.close_index();
606 void ResourcePixmap::draw_audio_source(TrackCanvas *canvas,
612 Indexable *indexable = edit->get_source();
613 double asset_over_session = (double)indexable->get_sample_rate() /
614 mwindow->edl->session->sample_rate;
615 int source_len = w * mwindow->edl->local_session->zoom_sample;
616 int center_pixel = mwindow->edl->local_session->zoom_track / 2;
617 if(mwindow->edl->session->show_titles)
618 center_pixel += mwindow->theme->get_image("title_bg_data")->get_h();
620 int64_t scale_y = mwindow->edl->local_session->zoom_y;
621 int y_max = canvas->get_h();
622 int max_y = center_pixel + scale_y / 2 - 1;
623 if( y_max > max_y ) y_max = max_y;
624 // Single sample zoom
625 if(mwindow->edl->local_session->zoom_sample == 1)
627 int64_t source_start = (int64_t)(((pixmap_x - edit_x + x) *
628 mwindow->edl->local_session->zoom_sample + edit->startsource) *
630 int total_source_samples = (int)((double)(source_len + 1) *
632 Samples *buffer = new Samples(total_source_samples);
634 canvas->set_color(mwindow->theme->audio_color);
636 if(indexable->is_asset)
638 File *source = mwindow->audio_cache->check_out(edit->asset, mwindow->edl);
642 printf(_("ResourcePixmap::draw_audio_source: failed to check out %s for drawing.\n"), edit->asset->path);
647 source->set_audio_position(source_start);
648 source->set_channel(edit->channel);
649 result = source->read_samples(buffer, total_source_samples);
650 mwindow->audio_cache->check_in(edit->asset);
654 if(mwindow->gui->render_engine &&
655 mwindow->gui->render_engine_id != indexable->id)
657 delete mwindow->gui->render_engine;
658 mwindow->gui->render_engine = 0;
661 if(!mwindow->gui->render_engine)
663 TransportCommand command;
664 command.command = NORMAL_FWD;
665 command.get_edl()->copy_all(edit->nested_edl);
666 command.change_type = CHANGE_ALL;
667 command.realtime = 0;
668 mwindow->gui->render_engine = new RenderEngine(0,
669 mwindow->preferences, 0, 0, 0);
670 mwindow->gui->render_engine_id = edit->nested_edl->id;
671 mwindow->gui->render_engine->set_acache(mwindow->audio_cache);
672 mwindow->gui->render_engine->arm_command(&command);
675 Samples *temp_buffer[MAX_CHANNELS];
676 bzero(temp_buffer, MAX_CHANNELS * sizeof(double*));
677 for(int i = 0; i < indexable->get_audio_channels(); i++)
679 temp_buffer[i] = new Samples(total_source_samples);
682 if(mwindow->gui->render_engine->arender)
684 mwindow->gui->render_engine->arender->process_buffer(
686 total_source_samples,
688 memcpy(buffer->get_data(),
689 temp_buffer[edit->channel]->get_data(),
690 total_source_samples * sizeof(double));
693 for(int i = 0; i < indexable->get_audio_channels(); i++)
695 delete temp_buffer[i];
704 double *samples = buffer->get_data();
705 int x2 = x, y = (int)(center_pixel - samples[0] * scale_y / 2);
706 int y2 = CLIP(y,0,y_max);
708 for(int i=1, x_max=x+w-1; x2<x_max; i++)
710 int x1 = x2, y1 = y2; ++x2;
711 int j = (int)(i * asset_over_session);
712 y = (int)(center_pixel - samples[j] * scale_y / 2);
713 y2 = CLIP(y, 0, y_max);
715 //printf("ResourcePixmap::draw_audio_source %d %d %d\n", __LINE__, y1, y2);
716 canvas->draw_line(x1, y1, x2, y2, this);
723 // Multiple sample zoom
730 canvas->set_color(mwindow->theme->audio_color);
731 // Draw each pixel from the cache
732 //printf("ResourcePixmap::draw_audio_source %d x=%d w=%d\n", __LINE__, x, w);
735 // Starting sample of pixel relative to asset rate.
736 int64_t source_start = (int64_t)(((pixmap_x - edit_x + x) *
737 mwindow->edl->local_session->zoom_sample + edit->startsource) *
739 int64_t source_end = (int64_t)(((pixmap_x - edit_x + x + 1) *
740 mwindow->edl->local_session->zoom_sample + edit->startsource) *
742 WaveCacheItem *item = mwindow->wave_cache->get_wave(indexable->id,
748 //printf("ResourcePixmap::draw_audio_source %d\n", __LINE__);
749 int y_lo = (int)(center_pixel - item->low * scale_y / 2);
750 int y1 = CLIP(y_lo, 0, y_max);
751 int y_hi = (int)(center_pixel - item->high * scale_y / 2);
752 int y2 = CLIP(y_hi, 0, y_max);
756 y_lo = MIN(y1,prev_y2);
757 y_hi = MAX(y2,prev_y1);
765 prev_y1 = y1; prev_y2 = y2;
766 canvas->draw_line(x, y_lo, x, y_hi, this);
768 //printf("ResourcePixmap::draw_audio_source %d %d %d %d\n", __LINE__, x, y1, y2);
770 mwindow->wave_cache->unlock();
774 //printf("ResourcePixmap::draw_audio_source %d\n", __LINE__);
776 gui->resource_thread->add_wave(this,
777 canvas->pane->number,
788 canvas->test_timer();
793 void ResourcePixmap::draw_wave(TrackCanvas *canvas,
799 if(mwindow->edl->session->show_titles)
800 top_pixel = mwindow->theme->get_image("title_bg_data")->get_h();
801 int center_pixel = mwindow->edl->local_session->zoom_track / 2 + top_pixel;
802 int bottom_pixel = top_pixel + mwindow->edl->local_session->zoom_track;
803 int y1 = (int)(center_pixel -
804 low * mwindow->edl->local_session->zoom_y / 2);
805 int y2 = (int)(center_pixel -
806 high * mwindow->edl->local_session->zoom_y / 2);
807 CLAMP(y1, top_pixel, bottom_pixel);
808 CLAMP(y2, top_pixel, bottom_pixel);
809 canvas->set_color(mwindow->theme->audio_color);
836 void ResourcePixmap::draw_video_resource(TrackCanvas *canvas,
847 //BC_Signals::dump_stack();
849 // pixels spanned by a picon
850 int64_t picon_w = Units::round(edit->picon_w());
851 int64_t picon_h = edit->picon_h();
854 // Don't draw video if picon is empty or bigger than edit
855 if( picon_w <= 0 || picon_w > edit_w ) return;
857 // pixels spanned by a frame
858 double frame_w = edit->frame_w();
860 // Frames spanned by a picon
861 double frames_per_picon = edit->frames_per_picon();
863 // Current pixel relative to pixmap
866 if(mwindow->edl->session->show_titles)
867 y += mwindow->theme->get_image("title_bg_data")->get_h();
868 // Frame in project touched by current pixel
869 int64_t project_frame;
871 // Get first frame touched by x and fix x to start of frame
872 if(frames_per_picon > 1)
874 int picon = Units::to_int64(
875 (double)((int64_t)refresh_x + pixmap_x - edit_x) /
877 x = picon_w * picon + edit_x - pixmap_x;
878 project_frame = Units::to_int64((double)picon * frames_per_picon);
882 project_frame = Units::to_int64((double)((int64_t)refresh_x + pixmap_x - edit_x) /
884 x = Units::round((double)project_frame * frame_w + edit_x - pixmap_x);
888 // Draw only cached frames
889 while(x < refresh_x + refresh_w)
891 int64_t source_frame = project_frame + edit->startsource;
892 VFrame *picon_frame = 0;
893 Indexable *indexable = edit->get_source();
901 picon_frame = mwindow->frame_cache->get_frame_ptr(source_frame,
903 mwindow->edl->session->frame_rate,
916 // Set picon thread to draw in background
917 if(mode != IGNORE_THREAD)
919 // printf("ResourcePixmap::draw_video_resource %d %d %lld\n",
921 // mwindow->frame_cache->total(),
923 gui->resource_thread->add_picon(this,
924 canvas->pane->number,
929 mwindow->edl->session->frame_rate,
937 draw_vframe(picon_frame,
946 // Unlock the get_frame_ptr command
948 mwindow->frame_cache->unlock();
950 if(frames_per_picon > 1)
952 x += Units::round(picon_w);
953 project_frame = Units::to_int64(frames_per_picon * (int64_t)((double)(x + pixmap_x - edit_x) / picon_w));
957 x += Units::round(frame_w);
958 project_frame = (int64_t)((double)(x + pixmap_x - edit_x) / frame_w);
962 canvas->test_timer();
968 void ResourcePixmap::draw_subttl_resource(TrackCanvas *canvas,
973 SEdit *sedit = (SEdit *)edit;
974 char *text = sedit->get_text();
975 if( !*text || w < 10 ) return;
976 int center_pixel = mwindow->edl->local_session->zoom_track / 2;
977 if(mwindow->edl->session->show_titles)
978 center_pixel += mwindow->theme->get_image("title_bg_data")->get_h();
979 int64_t scale_y = mwindow->edl->local_session->zoom_y;
981 if( x0 < 0 ) x0 = -x0;
982 int x1 = (int)(pixmap_x - x0 + x);
983 int y_max = canvas->get_h();
984 int max_y = center_pixel + scale_y / 2 - 1;
985 if( y_max > max_y ) y_max = max_y;
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 " _LX " edit_x " _LD " pixmap_x " _LD " pixmap_w " _LD " visible %d\n",
1000 edit_id, edit_x, pixmap_x, pixmap_w, visible);