4 * Copyright (C) 2009 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
23 #include "arraylist.h"
27 #include "indexfile.h"
28 #include "indexstate.h"
30 #include "mainerror.h"
36 int IndexMarks::find(int64_t no)
38 int l = -1, r = size();
39 while( (r - l) > 1 ) {
41 if( no > values[i].no ) l = i; else r = i;
46 IndexChannel::IndexChannel(IndexState *state, int64_t length)
49 this->length = length;
56 IndexChannel::~IndexChannel()
61 void IndexChannel::put_entry()
70 int64_t IndexChannel::pos()
72 return used() * state->index_zoom + zidx;
75 void IndexChannel::pad_data(int64_t pos)
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;
83 void IndexState::reset_index()
85 index_status = INDEX_NOTTESTED;
89 index_entries.remove_all_objects();
90 index_channels.remove_all_objects();
93 void IndexState::reset_markers()
95 marker_status = MARKERS_NOTTESTED;
96 video_markers.remove_all_objects();
97 audio_markers.remove_all_objects();
100 IndexState::IndexState()
101 : Garbage("IndexState")
103 marker_lock = new Mutex("IndexState::marker_lock");
108 IndexState::~IndexState()
115 void IndexState::init_scan(int64_t index_length)
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;
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;
137 void IndexState::dump()
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);
149 void IndexState::write_xml(FileXML *file)
151 file->tag.set_title("INDEX");
152 file->tag.set_property("ZOOM", index_zoom);
153 file->tag.set_property("BYTES", index_bytes);
155 file->append_newline();
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);
161 file->tag.set_title("/OFFSET");
163 file->tag.set_title("SIZE");
164 file->tag.set_property("FLOAT", index_entries[i]->size);
166 file->tag.set_title("/SIZE");
168 file->append_newline();
171 file->append_newline();
172 file->tag.set_title("/INDEX");
174 file->append_newline();
177 void IndexState::read_xml(FileXML *file, int channels)
179 index_entries.remove_all_objects();
180 for( int i=0; i<channels; ++i ) add_index_entry(0, 0, 0);
182 int current_offset = 0;
183 int current_size = 0;
186 index_zoom = file->tag.get_property("ZOOM", 1);
187 index_bytes = file->tag.get_property("BYTES", (int64_t)0);
190 result = file->read_tag();
192 if(file->tag.title_is("/INDEX")) {
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]);
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;
212 int IndexState::write_index(const char *index_path, Asset *asset, int64_t zoom, int64_t file_bytes)
214 FILE *fp = fopen(index_path, "wb");
216 eprintf(_("IndexState::write_index Couldn't write index file %s to disk.\n"),
221 index_bytes = file_bytes;
222 index_status = INDEX_READY;
225 // write index_state as asset or directly.
227 asset->write(&xml, 1, "");
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);
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);
249 int IndexState::write_markers(const char *index_path)
251 int vid_size = video_markers.size();
252 int aud_size = audio_markers.size();
253 if( !vid_size && !aud_size ) return 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, '.');
263 fp = fopen(marker_path, "wb");
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"),
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);
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);
293 int IndexState::read_markers(char *index_dir, char *file_path)
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);
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"),
310 ret = read_marks(fp);
311 if( !ret ) marker_status = MARKERS_READY;
315 marker_lock->unlock();
319 int IndexState::read_marks(FILE *fp)
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 ) {
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;
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 ) {
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;
349 int IndexState::create_index(const char *index_path, Asset *asset)
351 index_entries.remove_all_objects();
352 int channels = index_channels.size();
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);
362 write_markers(index_path);
363 return write_index(index_path, asset, index_zoom, index_bytes);
366 int64_t IndexState::get_index_offset(int channel)
368 return channel >= index_entries.size() ? 0 :
369 index_entries[channel]->offset;
372 int64_t IndexState::get_index_size(int channel)
374 return channel >= index_entries.size() ? 0 :
375 index_entries[channel]->size;
378 float *IndexState::get_channel_buffer(int channel)
380 return channel >= index_channels.size() ? 0 :
381 (float *)index_channels[channel]->bfr;
384 int64_t IndexState::get_channel_used(int channel)
386 return channel >= index_channels.size() ? 0 :
387 index_channels[channel]->used();