prevent popup deactivation while button_down
[goodguy/history.git] / cinelerra-5.0 / cinelerra / indexstate.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 2009 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
23 #include "arraylist.h"
24 #include "asset.h"
25 #include "clip.h"
26 #include "filexml.h"
27 #include "format.inc"
28 #include "indexfile.h"
29 #include "indexstate.h"
30 #include "language.h"
31 #include "mainerror.h"
32 #include "mutex.h"
33
34 #include <stdio.h>
35 #include <string.h>
36
37 int IndexMarks::find(int64_t no)
38 {
39         int l = -1, r = size();
40         while( (r - l) > 1 ) {
41                 int i = (l+r) >> 1;
42                 if( no > values[i].no ) l = i; else r = i;
43         }
44         return l;
45 }
46
47 IndexChannel::IndexChannel(IndexState *state, int64_t length)
48 {
49         this->state = state;
50         this->length = length;
51         min = max = 0;
52         bfr = inp = 0;
53         size = 0;
54         zidx = 0;
55 }
56
57 IndexChannel::~IndexChannel()
58 {
59         delete [] bfr;
60 }
61
62 void IndexChannel::put_entry()
63 {
64         inp->min = min;
65         inp->max = max;
66         ++inp;
67         max = -1; min = 1;
68         zidx = 0;
69 }
70
71 int64_t IndexChannel::pos()
72 {
73         return used() * state->index_zoom + zidx;
74 }
75
76 void IndexChannel::pad_data(int64_t pos)
77 {
78         CLAMP(pos, 0, length);
79         while( this->pos() < pos ) put_entry();
80         inp = bfr + pos / state->index_zoom;
81         zidx = pos % state->index_zoom;
82 }
83
84 void IndexState::reset_index()
85 {
86         index_status = INDEX_NOTTESTED;
87         index_start = 0;
88         index_zoom = 0;
89         index_bytes = 0;
90         index_entries.remove_all_objects();
91         index_channels.remove_all_objects();
92 }
93
94 void IndexState::reset_markers()
95 {
96         marker_status = MARKERS_NOTTESTED;
97         video_markers.remove_all_objects();
98         audio_markers.remove_all_objects();
99 }
100
101 IndexState::IndexState()
102  : Garbage("IndexState")
103 {
104         marker_lock = new Mutex("IndexState::marker_lock");
105         reset_index();
106         reset_markers();
107 }
108
109 IndexState::~IndexState()
110 {
111         reset_index();
112         reset_markers();
113         delete marker_lock;
114 }
115
116 void IndexState::init_scan(int64_t index_length)
117 {
118         index_zoom = 1;
119         int channels = index_channels.size();
120         if( !channels ) return;
121         int64_t max_samples = 0;
122         for( int ch=0; ch<channels; ++ch ) {
123                 int64_t len = index_channels[ch]->length;
124                 if( max_samples < len ) max_samples = len;
125         }
126         int64_t items = index_length / sizeof(IndexItem);
127         int64_t count = (items - channels) / channels + 1;
128         while( count*index_zoom < max_samples ) index_zoom *= 2;
129         for( int ch=0; ch<channels; ++ch ) {
130                 IndexChannel *chn = index_channels[ch];
131                 int64_t len = chn->length / index_zoom + 1;
132                 chn->alloc(len);
133                 chn->put_entry();
134         }
135         reset_markers();
136 }
137
138 void IndexState::dump()
139 {
140         printf("IndexState::dump this=%p\n", this);
141         printf("    index_status=%d index_zoom=" _LD " index_bytes=" _LD "\n",
142                 index_status, index_zoom, index_bytes);
143         printf("    index entries=%d\n", index_entries.size());
144         for( int i=0; i<index_entries.size(); ++i )
145                 printf("  %d. ofs=" _LD ", sz=" _LD "\n", i,
146                         index_entries[i]->offset, index_entries[i]->size);
147         printf("\n");
148 }
149
150 void IndexState::write_xml(FileXML *file)
151 {
152         file->tag.set_title("INDEX");
153         file->tag.set_property("ZOOM", index_zoom);
154         file->tag.set_property("BYTES", index_bytes);
155         file->append_tag();
156         file->append_newline();
157
158         for( int i=0; i<index_entries.size(); ++i ) {
159                 file->tag.set_title("OFFSET");
160                 file->tag.set_property("FLOAT", index_entries[i]->offset);
161                 file->append_tag();
162                 file->tag.set_title("SIZE");
163                 file->tag.set_property("FLOAT", index_entries[i]->size);
164                 file->append_tag();
165         }
166
167         file->append_newline();
168         file->tag.set_title("/INDEX");
169         file->append_tag();
170         file->append_newline();
171 }
172
173 void IndexState::read_xml(FileXML *file, int channels)
174 {
175         index_entries.remove_all_objects();
176         for( int i=0; i<channels; ++i ) add_index_entry(0, 0, 0);
177
178         int current_offset = 0;
179         int current_size = 0;
180         int result = 0;
181
182         index_zoom = file->tag.get_property("ZOOM", 1);
183         index_bytes = file->tag.get_property("BYTES", (int64_t)0);
184
185         while(!result) {
186                 result = file->read_tag();
187                 if(!result) {
188                         if(file->tag.title_is("/INDEX")) {
189                                 result = 1;
190                         }
191                         else if(file->tag.title_is("OFFSET")) {
192                                 if(current_offset < channels) {
193                                         int64_t offset = file->tag.get_property("FLOAT", (int64_t)0);
194                                         index_entries[current_offset++]->offset = offset;
195 //printf("Asset::read_index %d %d\n", current_offset - 1, index_offsets[current_offset - 1]);
196                                 }
197                         }
198                         else if(file->tag.title_is("SIZE")) {
199                                 if(current_size < channels) {
200                                         int64_t size = file->tag.get_property("FLOAT", (int64_t)0);
201                                         index_entries[current_size++]->size = size;
202                                 }
203                         }
204                 }
205         }
206 }
207
208 int IndexState::write_index(const char *index_path, Asset *asset, int64_t zoom, int64_t file_bytes)
209 {
210         FILE *fp = fopen(index_path, "wb");
211         if( !fp ) {
212                 eprintf(_("IndexState::write_index Couldn't write index file %s to disk.\n"),
213                         index_path);
214                 return 1;
215         }
216         index_zoom = zoom;
217         index_bytes = file_bytes;
218         index_status = INDEX_READY;
219
220         FileXML xml;
221 // write index_state as asset or directly.
222         if( asset )
223                 asset->write(&xml, 1, "");
224         else
225                 write_xml(&xml);
226         int64_t len = xml.length() + FileXML::xml_header_size;
227         index_start = sizeof(index_start) + len;
228         fwrite(&index_start, sizeof(index_start), 1, fp);
229         xml.write_to_file(fp);
230
231         int channels = index_entries.size();
232         int64_t max_size = 0;
233         for( int ch=0; ch<channels; ++ch ) {
234                 IndexEntry *ent = index_entries[ch];
235                 float *bfr = ent->bfr;
236                 int64_t size = ent->size;
237                 if( max_size < size ) max_size = size;
238                 fwrite(bfr, sizeof(float), size, fp);
239         }
240
241         fclose(fp);
242         reset_index();
243         return 0;
244 }
245
246 int IndexState::write_markers(const char *index_path)
247 {
248         int vid_size = video_markers.size();
249         int aud_size = audio_markers.size();
250         if( !vid_size && !aud_size ) return 0;
251
252         FILE *fp = 0;
253         char marker_path[BCTEXTLEN];
254         strcpy(marker_path, index_path);
255         char *basename = strrchr(marker_path,'/');
256         if( !basename ) basename = marker_path;
257         char *ext = strrchr(basename, '.');
258         if( ext ) {
259                 strcpy(ext, ".mkr");
260                 fp = fopen(marker_path, "wb");
261         }
262
263         char version[] = MARKER_MAGIC_VERSION;
264         if( !fp || !fwrite(version, strlen(version), 1, fp) ) {
265                 eprintf(_("IndexState::write_markers Couldn't write marker file %s to disk.\n"),
266                         marker_path);
267                 return 1;
268         }
269
270         fwrite(&vid_size, sizeof(vid_size), 1, fp);
271         for( int vidx=0; vidx<vid_size; ++vidx ) {
272                 IndexMarks &marks = *video_markers[vidx];
273                 int count = marks.size();
274                 fwrite(&count, sizeof(count), 1, fp);
275                 fwrite(&marks[0], sizeof(marks[0]), count, fp);
276         }
277
278         fwrite(&aud_size, sizeof(aud_size), 1, fp);
279         for( int aidx=0; aidx<aud_size; ++aidx ) {
280                 IndexMarks &marks = *audio_markers[aidx];
281                 int count = marks.size();
282                 fwrite(&count, sizeof(count), 1, fp);
283                 fwrite(&marks[0], sizeof(marks[0]), marks.size(), fp);
284         }
285
286         fclose(fp);
287         return 0;
288 }
289
290 int IndexState::read_markers(char *index_dir, char *file_path)
291 {
292         int ret = 0;
293         marker_lock->lock("IndexState::read_markers");
294         if( marker_status == MARKERS_NOTTESTED ) {
295                 char src_path[BCTEXTLEN], marker_path[BCTEXTLEN];
296                 IndexFile::get_index_filename(src_path, index_dir, marker_path, file_path, ".mkr");
297                 FILE *fp = fopen(marker_path, "rb");
298                 int vsz = strlen(MARKER_MAGIC_VERSION);
299                 char version[vsz];
300                 if( fp && fread(version, vsz, 1, fp) ) {
301                         if( memcmp(version, MARKER_MAGIC_VERSION, vsz) ) {
302                                 eprintf(_("IndexState::read_markers marker file version mismatched\n: %s\n"),
303                                         marker_path);
304                                 return 1;
305                         }
306                         ret = read_marks(fp);
307                         if( !ret ) marker_status = MARKERS_READY;
308                         fclose(fp);
309                 }
310         }
311         marker_lock->unlock();
312         return ret;
313 }
314
315 int IndexState::read_marks(FILE *fp)
316 {
317         reset_markers();
318         int vid_size = 0;
319         if( !fread(&vid_size, sizeof(vid_size), 1, fp) ) return 1;
320         add_video_markers(vid_size);
321         for( int vidx=0; vidx<vid_size; ++vidx ) {
322                 int count = 0;
323                 if( !fread(&count, sizeof(count), 1, fp) ) return 1;
324                 IndexMarks &marks = *video_markers[vidx];
325                 marks.allocate(count);
326                 int len = fread(&marks[0], sizeof(marks[0]), count, fp);
327                 if( len != count ) return 1;
328                 marks.total = count;
329         }
330         int aud_size = 0;
331         if( !fread(&aud_size, sizeof(aud_size), 1, fp) ) return 1;
332         add_audio_markers(aud_size);
333         for( int aidx=0; aidx<aud_size; ++aidx ) {
334                 int count = 0;
335                 if( !fread(&count, sizeof(count), 1, fp) ) return 1;
336                 IndexMarks &marks = *audio_markers[aidx];
337                 marks.allocate(count);
338                 int len = fread(&marks[0], sizeof(marks[0]), count, fp);
339                 if( len != count ) return 1;
340                 marks.total = count;
341         }
342         return 0;
343 }
344
345 int IndexState::create_index(const char *index_path, Asset *asset)
346 {
347         index_entries.remove_all_objects();
348         int channels = index_channels.size();
349         int64_t offset = 0;
350         for( int ch=0; ch<channels; ++ch ) {
351                 IndexChannel *chn = index_channels[ch];
352                 float *bfr = (float *)chn->bfr;
353                 int64_t size = 2 * chn->used();
354                 add_index_entry(bfr, offset, size);
355                 offset += size;
356         }
357
358         write_markers(index_path);
359         return write_index(index_path, asset, index_zoom, index_bytes);
360 }
361
362 int64_t IndexState::get_index_offset(int channel)
363 {
364         return channel >= index_entries.size() ? 0 :
365                 index_entries[channel]->offset;
366 }
367
368 int64_t IndexState::get_index_size(int channel)
369 {
370         return channel >= index_entries.size() ? 0 :
371                 index_entries[channel]->size;
372 }
373
374 float *IndexState::get_channel_buffer(int channel)
375 {
376         return channel >= index_channels.size() ? 0 :
377                 (float *)index_channels[channel]->bfr;
378 }
379
380 int64_t IndexState::get_channel_used(int channel)
381 {
382         return channel >= index_channels.size() ? 0 :
383                 index_channels[channel]->used();
384 }
385