61e81cb5e48070f76c3ec0a871d2ba6c883b2275
[goodguy/history.git] / cinelerra-5.1 / cinelerra / indexfile.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 1997-2014 Adam Williams <broadcast at earthling dot net>
5  *
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.
10  *
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.
15  *
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
19  *
20  */
21
22 #include "arender.h"
23 #include "asset.h"
24 #include "bcsignals.h"
25 #include "bctimer.h"
26 #include "cache.h"
27 #include "clip.h"
28 #include "condition.h"
29 #include "edit.h"
30 #include "edl.h"
31 #include "edlsession.h"
32 #include "errorbox.h"
33 #include "file.h"
34 #include "filesystem.h"
35 #include "filexml.h"
36 #include "indexable.h"
37 #include "indexfile.h"
38 #include "indexstate.h"
39 #include "indexthread.h"
40 #include "language.h"
41 #include "localsession.h"
42 #include "mainprogress.h"
43 #include "mwindowgui.h"
44 #include "mwindow.h"
45 #include "preferences.h"
46 #include "removefile.h"
47 #include "renderengine.h"
48 #include "resourcepixmap.h"
49 #include "samples.h"
50 #include "theme.h"
51 #include "timelinepane.h"
52 #include "trackcanvas.h"
53 #include "tracks.h"
54 #include "transportque.h"
55 #include "vframe.h"
56
57
58 #include <stdio.h>
59 #include <stdlib.h>
60 #include <stdint.h>
61 #include <unistd.h>
62 #include <string.h>
63 #include <errno.h>
64 #include <fcntl.h>
65 #include <ctype.h>
66
67 #include <sys/types.h>
68 #include <sys/stat.h>
69 #include <linux/iso_fs.h>
70
71 // check for isofs volume_id for dvd/cdrom
72
73 static int udf_volume_id(const char *path, char *fname)
74 {
75         struct stat st;
76         if( stat(path,&st) ) return 1;
77         // search mounted devices
78         FILE *fp = fopen("/proc/mounts","r");
79         if( !fp ) return 1;
80
81         int result = 1;
82         while( result && !feof(fp) && !ferror(fp) ) {
83                 char devpath[BCTEXTLEN], mpath[BCTEXTLEN];
84                 char options[BCTEXTLEN], line[BCTEXTLEN];
85                 char fstype[64], zero1[16], zero2[16];
86                 if( !fgets(&line[0], sizeof(line)-1, fp) ) break;
87                 int n = sscanf(&line[0], "%s %s %s %s %s %s\n",
88                          devpath, mpath, fstype, options, zero1, zero2);
89                 if( n != 6 ) continue;
90                 // check udf filesystems
91                 if( strcmp(fstype,"udf") != 0 ) continue;
92                 struct stat dst;
93                 if( stat(devpath,&dst) ) continue;
94                 if( st.st_dev != dst.st_rdev ) continue;
95                 int fd = open(devpath,O_RDONLY);
96                 if( fd < 0 ) continue;
97                 struct iso_primary_descriptor id;
98                 if( lseek(fd,0x8000,SEEK_SET) == 0x8000 )
99                         n = read(fd,&id,sizeof(id));
100                 close(fd);
101                 if( n != sizeof(id) ) continue;
102                 // look for magic number
103                 if( strncmp(ISO_STANDARD_ID,id.id,sizeof(id.id)) ) continue;
104                 // look for volume_id
105                 if( !isalnum(id.volume_id[0]) ) continue;
106                 char *bp = &id.volume_id[0], *cp = fname;
107                 for( int i=0; i<(int)sizeof(id.volume_id); ++i ) *cp++ = *bp++;
108                 while( --cp>=fname && *cp==' ' ) *cp = 0;
109                 if( !*fname ) continue;
110                 // fname = volume_id _ creation_date
111                 ++cp;  *cp++ = '_';  bp = &id.creation_date[0];
112                 for( int i=0; i<(int)sizeof(id.creation_date)-1; ++i ) {
113                         if( !isdigit(*bp) ) break;
114                         *cp++ = *bp++;
115                 }
116                 *cp++ = 0;
117                 if( cp-fname > 4 ) result = 0;
118         }
119
120         fclose(fp);
121         return result;
122 }
123
124 // Use native sampling rates for files so the same index can be used in
125 // multiple projects.
126
127 IndexFile::IndexFile(MWindow *mwindow)
128 {
129 //printf("IndexFile::IndexFile 1\n");
130         reset();
131         this->mwindow = mwindow;
132 //printf("IndexFile::IndexFile 2\n");
133         redraw_timer = new Timer;
134 }
135
136 IndexFile::IndexFile(MWindow *mwindow,
137         Indexable *indexable)
138 {
139 //printf("IndexFile::IndexFile 2\n");
140         reset();
141         this->mwindow = mwindow;
142         this->indexable = indexable;
143         redraw_timer = new Timer;
144         if(indexable)
145         {
146                 indexable->add_user();
147                 source_channels = indexable->get_audio_channels();
148                 source_samplerate = indexable->get_sample_rate();
149                 source_length = indexable->get_audio_samples();
150         }
151 }
152
153 IndexFile::~IndexFile()
154 {
155 //printf("IndexFile::~IndexFile 1\n");
156         delete redraw_timer;
157         if(indexable) indexable->remove_user();
158         close_source();
159 }
160
161 void IndexFile::reset()
162 {
163         fd = 0;
164         source = 0;
165         interrupt_flag = 0;
166         source_length = 0;
167         source_channels = 0;
168         indexable = 0;
169         render_engine = 0;
170         cache = 0;
171 }
172
173 IndexState* IndexFile::get_state()
174 {
175         IndexState *index_state = 0;
176         if(indexable) index_state = indexable->index_state;
177         return index_state;
178 }
179
180
181
182 int IndexFile::open_index()
183 {
184         IndexState *index_state = 0;
185         int result = 0;
186
187 // use buffer if being built
188         index_state = get_state();
189
190         if(index_state->index_status == INDEX_BUILDING)
191         {
192 // use buffer
193                 result = 0;
194         }
195         else
196         if(!(result = open_file()))
197         {
198 // opened existing file
199                 if(read_info())
200                 {
201                         result = 1;
202                         close_index();
203                 }
204                 else
205                 {
206                         index_state->index_status = INDEX_READY;
207                 }
208         }
209         else
210         {
211                 result = 1;
212         }
213
214         return result;
215 }
216
217 void IndexFile::delete_index(Preferences *preferences,
218         Indexable *indexable, const char *suffix)
219 {
220         char index_filename[BCTEXTLEN];
221         char source_filename[BCTEXTLEN];
222         const char *path = indexable->path;
223
224         get_index_filename(source_filename,
225                 preferences->index_directory,
226                 index_filename, path, suffix);
227 //printf("IndexFile::delete_index %s %s\n", source_filename, index_filename);
228         remove_file(index_filename);
229 }
230
231 int IndexFile::open_file()
232 {
233         int result = 0;
234         const int debug = 0;
235         const char *path = indexable->path;
236
237
238 //printf("IndexFile::open_file %f\n", indexable->get_frame_rate());
239
240         get_index_filename(source_filename,
241                 mwindow->preferences->index_directory,
242                 index_filename,
243                 path);
244
245         if(debug) printf("IndexFile::open_file %d index_filename=%s\n",
246                 __LINE__,
247                 index_filename);
248         fd = fopen(index_filename, "rb");
249         if( fd != 0 )
250         {
251 // Index file already exists.
252 // Get its last size without changing the real asset status.
253                 Indexable *test_indexable = new Indexable(0);
254                 if(indexable)
255                         test_indexable->copy_indexable(indexable);
256                 read_info(test_indexable);
257                 IndexState *index_state = test_indexable->index_state;
258
259                 FileSystem fs;
260                 if(fs.get_date(index_filename) < fs.get_date(test_indexable->path))
261                 {
262                         if(debug) printf("IndexFile::open_file %d index_date=%jd source_date=%jd\n",
263                                 __LINE__,
264                                 fs.get_date(index_filename),
265                                 fs.get_date(test_indexable->path));
266
267 // index older than source
268                         result = 2;
269                         fclose(fd);
270                         fd = 0;
271                 }
272                 else
273                 if(fs.get_size(test_indexable->path) != index_state->index_bytes)
274                 {
275 // source file is a different size than index source file
276                         if(debug) printf("IndexFile::open_file %d index_size=%jd source_size=%jd\n",
277                                 __LINE__,
278                                 index_state->index_bytes,
279                                 fs.get_size(test_indexable->path));
280                         result = 2;
281                         fclose(fd);
282                         fd = 0;
283                 }
284                 else
285                 {
286                         if(debug) printf("IndexFile::open_file %d\n",
287                                 __LINE__);
288                         fseek(fd, 0, SEEK_END);
289                         file_length = ftell(fd);
290                         fseek(fd, 0, SEEK_SET);
291                         result = 0;
292                 }
293                 test_indexable->Garbage::remove_user();
294         }
295         else
296         {
297 // doesn't exist
298                 if(debug) printf("IndexFile::open_file %d index_filename=%s doesn't exist\n",
299                         __LINE__,
300                         index_filename);
301                 result = 1;
302         }
303
304         return result;
305 }
306
307 int IndexFile::open_source()
308 {
309 //printf("IndexFile::open_source %p %s\n", asset, asset->path);
310         int result = 0;
311         if(indexable && indexable->is_asset)
312         {
313                 if(!source) source = new File;
314
315                 Asset *asset = (Asset*)indexable;
316                 if(source->open_file(mwindow->preferences,
317                         asset, 1, 0))
318                 {
319                         //printf("IndexFile::open_source() Couldn't open %s.\n", asset->path);
320                         result = 1;
321                 }
322                 else
323                 {
324                         FileSystem fs;
325                         asset->index_state->index_bytes = fs.get_size(asset->path);
326                         source_length = source->get_audio_length();
327                 }
328         }
329         else
330         {
331                 TransportCommand command;
332                 command.command = NORMAL_FWD;
333                 command.get_edl()->copy_all((EDL*)indexable);
334                 command.change_type = CHANGE_ALL;
335                 command.realtime = 0;
336                 cache = new CICache(mwindow->preferences);
337                 render_engine = new RenderEngine(0,
338                         mwindow->preferences, 0, 0);
339                 render_engine->set_acache(cache);
340                 render_engine->arm_command(&command);
341                 FileSystem fs;
342                 indexable->index_state->index_bytes = fs.get_size(indexable->path);
343         }
344
345         return result;
346 }
347
348 void IndexFile::close_source()
349 {
350         delete source;
351         source = 0;
352
353         delete render_engine;
354         render_engine = 0;
355
356         delete cache;
357         cache = 0;
358 }
359
360 int64_t IndexFile::get_required_scale()
361 {
362         int64_t result = 1;
363
364
365 // get scale of index file
366 // Total peaks which may be stored in buffer
367         int64_t peak_count = mwindow->preferences->index_size /
368                 (2 * sizeof(float) * source_channels);
369         for(result = 1;
370                 source_length / result > peak_count;
371                 result *= 2)
372                 ;
373
374 // Takes too long to draw from source on a CDROM.  Make indexes for
375 // everything.
376
377         return result;
378 }
379
380 int IndexFile::get_index_filename(char *source_filename,
381         char *index_directory,
382         char *index_filename,
383         const char *input_filename,
384         const char *suffix)
385 {
386         const char *input_fn = input_filename;
387         char volume_id[BCTEXTLEN];
388 // Replace mount/directory with volume_id if isofs
389         if( !udf_volume_id(input_filename, volume_id) )
390         {
391                 char *cp = strrchr((char*)input_filename,'/');
392                 if( cp ) input_fn = cp + 1;
393                 for( cp=volume_id; *cp; ++cp );
394                 *cp++ = '_';  strcpy(cp, input_fn);
395                 input_fn = volume_id;
396         }
397 // Replace slashes and dots
398         int i, j;
399         int len = strlen(input_fn);
400         for(i = 0, j = 0; i < len; i++)
401         {
402                 if(input_fn[i] != '/' &&
403                         input_fn[i] != '.')
404                         source_filename[j++] = input_fn[i];
405                 else
406                 {
407                         if(i > 0)
408                                 source_filename[j++] = '_';
409                 }
410         }
411         source_filename[j] = 0;
412         FileSystem fs;
413         fs.join_names(index_filename, index_directory, source_filename);
414         strcat(index_filename, suffix ? suffix : ".idx");
415         return 0;
416 }
417
418 int IndexFile::interrupt_index()
419 {
420         interrupt_flag = 1;
421         return 0;
422 }
423
424 // Read data into buffers
425
426 int IndexFile::create_index(MainProgressBar *progress)
427 {
428         int result = 0;
429 SET_TRACE
430
431         interrupt_flag = 0;
432
433 // open the source file
434         if(open_source()) return 1;
435         source_channels = indexable->get_audio_channels();
436         source_samplerate = indexable->get_sample_rate();
437         source_length = indexable->get_audio_samples();
438
439 SET_TRACE
440
441         get_index_filename(source_filename,
442                 mwindow->preferences->index_directory,
443                 index_filename,
444                 indexable->path);
445
446 SET_TRACE
447
448 // Some file formats have their own sample index.
449 // Test for index in stream table of contents
450         if(source && !source->get_index(this, progress))
451         {
452                 IndexState *index_state = get_state();
453                 index_state->index_status = INDEX_READY;
454                 redraw_edits(1);
455         }
456         else
457 // Build index from scratch
458         {
459 SET_TRACE
460
461 // Indexes are now built for everything since it takes too long to draw
462 // from CDROM source.
463
464 // get amount to read at a time in floats
465                 int64_t buffersize = 65536;
466                 char string[BCTEXTLEN];
467                 sprintf(string, _("Creating %s."), index_filename);
468
469                 progress->update_title(string);
470                 progress->update_length(source_length);
471                 redraw_timer->update();
472 SET_TRACE
473
474 // thread out index thread
475                 IndexThread *index_thread = new IndexThread(mwindow,
476                         this,
477                         index_filename,
478                         buffersize,
479                         source_length);
480                 index_thread->start_build();
481
482 // current sample in source file
483                 int64_t position = 0;
484                 int64_t fragment_size = buffersize;
485                 int current_buffer = 0;
486
487
488 // pass through file once
489 // printf("IndexFile::create_index %d source_length=%jd source=%p progress=%p\n",
490 // __LINE__,
491 // source_length,
492 // source,
493 // progress);
494 SET_TRACE
495                 while(position < source_length && !result)
496                 {
497 SET_TRACE
498                         if(source_length - position < fragment_size && fragment_size == buffersize) fragment_size = source_length - position;
499
500                         index_thread->input_lock[current_buffer]->lock("IndexFile::create_index 1");
501                         index_thread->input_len[current_buffer] = fragment_size;
502
503 SET_TRACE
504                         int cancelled = progress->update(position);
505 //printf("IndexFile::create_index cancelled=%d\n", cancelled);
506 SET_TRACE
507                         if(cancelled ||
508                                 index_thread->interrupt_flag ||
509                                 interrupt_flag)
510                         {
511                                 result = 3;
512                         }
513
514
515 SET_TRACE
516                         if(source && !result)
517                         {
518 SET_TRACE
519                                 for(int channel = 0;
520                                         !result && channel < source_channels;
521                                         channel++)
522                                 {
523 // Read from source file
524                                         source->set_audio_position(position);
525                                         source->set_channel(channel);
526
527                                         if(source->read_samples(
528                                                 index_thread->buffer_in[current_buffer][channel],
529                                                 fragment_size))
530                                                 result = 1;
531                                 }
532 SET_TRACE
533                         }
534                         else
535                         if(render_engine && !result)
536                         {
537 SET_TRACE
538                                 if(render_engine->arender)
539                                 {
540                                         result = render_engine->arender->process_buffer(
541                                                 index_thread->buffer_in[current_buffer],
542                                                 fragment_size,
543                                                 position);
544                                 }
545                                 else
546                                 {
547                                         for(int i = 0; i < source_channels; i++)
548                                         {
549                                                 bzero(index_thread->buffer_in[current_buffer][i]->get_data(),
550                                                         fragment_size * sizeof(double));
551                                         }
552                                 }
553 SET_TRACE
554                         }
555 SET_TRACE
556
557 // Release buffer to thread
558                         if(!result)
559                         {
560                                 index_thread->output_lock[current_buffer]->unlock();
561                                 current_buffer++;
562                                 if(current_buffer >= TOTAL_INDEX_BUFFERS) current_buffer = 0;
563                                 position += fragment_size;
564                         }
565                         else
566                         {
567                                 index_thread->input_lock[current_buffer]->unlock();
568                         }
569 SET_TRACE
570                 }
571
572
573 // end thread cleanly
574                 index_thread->input_lock[current_buffer]->lock("IndexFile::create_index 2");
575                 index_thread->last_buffer[current_buffer] = 1;
576                 index_thread->output_lock[current_buffer]->unlock();
577                 index_thread->stop_build();
578
579
580                 delete index_thread;
581
582         }
583
584
585
586         close_source();
587
588
589
590         open_index();
591
592         close_index();
593
594         mwindow->edl->set_index_file(indexable);
595         return 0;
596 }
597
598
599
600 int IndexFile::redraw_edits(int force)
601 {
602         int64_t difference = redraw_timer->get_scaled_difference(1000);
603
604         if(difference > 250 || force)
605         {
606                 redraw_timer->update();
607                 mwindow->gui->lock_window("IndexFile::redraw_edits");
608                 mwindow->edl->set_index_file(indexable);
609                 mwindow->gui->draw_indexes(indexable);
610                 mwindow->gui->unlock_window();
611         }
612         return 0;
613 }
614
615
616
617
618 int IndexFile::draw_index(
619         TrackCanvas *canvas,
620         ResourcePixmap *pixmap,
621         Edit *edit,
622         int x,
623         int w)
624 {
625         const int debug = 0;
626         IndexState *index_state = get_state();
627         int pane_number = canvas->pane->number;
628 //index_state->dump();
629
630 SET_TRACE
631         if(debug) printf("IndexFile::draw_index %d\n", __LINE__);
632         if(index_state->index_zoom == 0)
633         {
634                 printf(_("IndexFile::draw_index: index has 0 zoom\n"));
635                 return 0;
636         }
637         if(debug) printf("IndexFile::draw_index %d\n", __LINE__);
638
639 // test channel number
640         if(edit->channel > source_channels) return 1;
641         if(debug) printf("IndexFile::draw_index %d source_samplerate=%d "
642                         "w=%d samplerate=%jd zoom_sample=%jd\n",
643                 __LINE__, source_samplerate, w,
644                 mwindow->edl->session->sample_rate,
645                 mwindow->edl->local_session->zoom_sample);
646
647 // calculate a virtual x where the edit_x should be in floating point
648         double virtual_edit_x = 1.0 *
649                 edit->track->from_units(edit->startproject) *
650                 mwindow->edl->session->sample_rate /
651                 mwindow->edl->local_session->zoom_sample -
652                 mwindow->edl->local_session->view_start[pane_number];
653
654 // samples in segment to draw relative to asset
655         double asset_over_session = (double)source_samplerate /
656                 mwindow->edl->session->sample_rate;
657         int64_t startsource = (int64_t)(((pixmap->pixmap_x - virtual_edit_x + x) *
658                 mwindow->edl->local_session->zoom_sample +
659                 edit->startsource) *
660                 asset_over_session);
661 // just in case we get a numerical error
662         if (startsource < 0) startsource = 0;
663         int64_t length = (int64_t)(w *
664                 mwindow->edl->local_session->zoom_sample *
665                 asset_over_session);
666         int64_t lengthindex = length / index_state->index_zoom * 2;
667         int64_t startindex = startsource / index_state->index_zoom * 2;
668 // length of index to read in floats
669 // length of index available in floats
670         int64_t endindex = index_state->index_status == INDEX_BUILDING ?
671                 index_state->get_channel_used(edit->channel) * 2 :
672                 index_state->get_index_size(edit->channel);
673 // Clamp length of index to read by available data
674         if(startindex + lengthindex >= endindex )
675                 lengthindex = endindex - startindex;
676         if( lengthindex <= 0 ) return 0;
677
678 // Actual length read from file in bytes
679         int64_t length_read;
680 // Start and length of fragment to read from file in bytes.
681         int64_t startfile, lengthfile;
682         float *buffer = 0;
683         int buffer_shared = 0;
684         int center_pixel = mwindow->edl->local_session->zoom_track / 2;
685         if( mwindow->edl->session->show_titles )
686                 center_pixel += mwindow->theme->get_image("title_bg_data")->get_h();
687         //int miny = center_pixel - mwindow->edl->local_session->zoom_track / 2;
688         //int maxy = center_pixel + mwindow->edl->local_session->zoom_track / 2;
689         int x1 = 0, y1, y2;
690 // get zoom_sample relative to index zoomx
691         double index_frames_per_pixel = mwindow->edl->local_session->zoom_sample /
692                 index_state->index_zoom *
693                 asset_over_session;
694
695
696
697         if(index_state->index_status == INDEX_BUILDING)
698         {
699 // index is in RAM, being built
700                 buffer = index_state->get_channel_buffer(edit->channel);
701                 if( !buffer ) return 0;
702                 buffer += startindex;
703                 buffer_shared = 1;
704         }
705         else
706         {
707 // add channel offset
708                 startindex += index_state->get_index_offset(edit->channel);
709 // index is stored in a file
710                 buffer = new float[lengthindex + 1];
711                 buffer_shared = 0;
712                 startfile = index_state->index_start + startindex * sizeof(float);
713                 lengthfile = lengthindex * sizeof(float);
714                 length_read = 0;
715
716                 if(startfile < file_length)
717                 {
718                         fseek(fd, startfile, SEEK_SET);
719
720                         length_read = lengthfile;
721                         if(startfile + length_read > file_length)
722                                 length_read = file_length - startfile;
723
724                         (void)fread(buffer, length_read + sizeof(float), 1, fd);
725                 }
726
727                 if(length_read < lengthfile) {
728                         int pos = length_read / sizeof(float);
729                         int file_length = lengthfile / sizeof(float);
730                         while( pos < file_length ) buffer[pos++] = 0;
731                 }
732         }
733
734         canvas->set_color(mwindow->theme->audio_color);
735
736         double current_frame = 0;
737         float highsample = buffer[0];
738         float lowsample = buffer[1];
739         int prev_y1 = center_pixel;
740         int prev_y2 = center_pixel;
741         int first_frame = 1;
742         int zoom_y = mwindow->edl->local_session->zoom_y, zoom_y2 = zoom_y / 2;
743         int max_y = center_pixel + zoom_y2 - 1;
744 SET_TRACE
745
746         for(int bufferposition = 0;
747                 bufferposition < lengthindex;
748                 bufferposition += 2)
749         {
750                 if(current_frame >= index_frames_per_pixel)
751                 {
752
753                         int y1 = (int)(center_pixel - highsample * zoom_y2);
754                         int y2 = (int)(center_pixel - lowsample * zoom_y2);
755                         CLAMP(y1, 0, max_y);  int next_y1 = y1;
756                         CLAMP(y2, 0, max_y);  int next_y2 = y2;
757 //printf("draw_line (%f,%f) = %d,%d,  %d,%d\n", lowsample, highsample, x1 + x, y1, x1 + x, y2);
758
759 //SET_TRACE
760 // A different algorithm has to be used if it's 1 sample per pixel and the
761 // index is used.  Now the min and max values are equal so we join the max samples.
762                         if(mwindow->edl->local_session->zoom_sample == 1)
763                         {
764                                 canvas->draw_line(x1 + x - 1, prev_y1, x1 + x, y1, pixmap);
765                         }
766                         else
767                         {
768 // Extend line height if it doesn't connect to previous line
769                                 if(!first_frame)
770                                 {
771                                         if(y1 > prev_y2) y1 = prev_y2 + 1;
772                                         if(y2 < prev_y1) y2 = prev_y1 - 1;
773                                 }
774                                 else
775                                 {
776                                         first_frame = 0;
777                                 }
778
779
780
781                                 canvas->draw_line(x1 + x, y1, x1 + x, y2, pixmap);
782                         }
783                         current_frame -= index_frames_per_pixel;
784                         x1++;
785                         prev_y1 = next_y1;
786                         prev_y2 = next_y2;
787                         highsample = buffer[bufferposition];
788                         lowsample = buffer[bufferposition + 1];
789                 }
790
791                 current_frame++;
792                 highsample = MAX(highsample, buffer[bufferposition]);
793                 lowsample = MIN(lowsample, buffer[bufferposition + 1]);
794         }
795 SET_TRACE
796
797 // Get last column
798         if(current_frame)
799         {
800                 y1 = (int)(center_pixel - highsample * zoom_y2);
801                 y2 = (int)(center_pixel - lowsample * zoom_y2);
802                 canvas->draw_line(x1 + x, y1, x1 + x, y2, pixmap);
803         }
804
805 SET_TRACE
806
807
808
809         if(!buffer_shared) delete [] buffer;
810 SET_TRACE
811         if(debug) printf("IndexFile::draw_index %d\n", __LINE__);
812         return 0;
813 }
814
815 int IndexFile::close_index()
816 {
817         if(fd)
818         {
819                 fclose(fd);
820                 fd = 0;
821         }
822         return 0;
823 }
824
825 int IndexFile::remove_index()
826 {
827         IndexState *index_state = get_state();
828         if(index_state->index_status == INDEX_READY ||
829                 index_state->index_status == INDEX_NOTTESTED)
830         {
831                 close_index();
832                 remove(index_filename);
833         }
834         return 0;
835 }
836
837 int IndexFile::read_info(Indexable *test_indexable)
838 {
839         const int debug = 0;
840
841 // Store format in actual asset.
842 // If it's a nested EDL, we never want the format, just the index info.
843         if(!test_indexable) test_indexable = indexable;
844         if(!test_indexable) return 1;
845
846         IndexState * index_state = test_indexable->index_state;
847         if(index_state->index_status == INDEX_NOTTESTED)
848         {
849 // read start of index data
850                 int temp = fread((char*)&(index_state->index_start), sizeof(int64_t), 1, fd);
851 //printf("IndexFile::read_info %d %f\n", __LINE__, test_indexable->get_frame_rate());
852
853                 if(!temp) return 1;
854 // read test_indexable info from index
855                 char *data;
856
857                 data = new char[index_state->index_start];
858                 temp = fread(data, index_state->index_start - sizeof(int64_t), 1, fd);
859                 if(!temp) return 1;
860
861                 data[index_state->index_start - sizeof(int64_t)] = 0;
862                 FileXML xml;
863                 xml.read_from_string(data);
864                 delete [] data;
865
866
867
868 // Read the file format & index state.
869                 if(test_indexable->is_asset)
870                 {
871                         Asset *test_asset = (Asset *)test_indexable;
872                         Asset *asset = new Asset;
873                         asset->read(&xml);
874                         int ret = 0;
875 //printf("IndexFile::read_info %d %f\n", __LINE__, asset->get_frame_rate());
876
877                         if( asset->format == FILE_UNKNOWN ||
878                             test_asset->format != asset->format ) {
879 if(debug) printf("IndexFile::read_info %d\n", __LINE__);
880                                 ret = 1;
881                         }
882                         asset->remove_user();
883                         if( ret ) return ret;
884                 }
885                 else
886                 {
887 // Read only the index state for a nested EDL
888                         int result = 0;
889 if(debug) printf("IndexFile::read_info %d\n", __LINE__);
890                         while(!result)
891                         {
892                                 result = xml.read_tag();
893                                 if(!result)
894                                 {
895                                         if(xml.tag.title_is("INDEX"))
896                                         {
897                                                 index_state->read_xml(&xml, source_channels);
898 if(debug) printf("IndexFile::read_info %d\n", __LINE__);
899 if(debug) index_state->dump();
900                                                 result = 1;
901                                         }
902                                 }
903                         }
904                 }
905         }
906
907         return 0;
908 }
909
910
911
912
913
914
915
916