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