add ffmpeg indexing
authorGood Guy <good1.2guy@gmail.com>
Fri, 25 Sep 2015 20:19:56 +0000 (14:19 -0600)
committerGood Guy <good1.2guy@gmail.com>
Fri, 25 Sep 2015 20:19:56 +0000 (14:19 -0600)
41 files changed:
cinelerra-5.0/cinelerra/asset.C
cinelerra-5.0/cinelerra/asset.h
cinelerra-5.0/cinelerra/audioalsa.C
cinelerra-5.0/cinelerra/awindowgui.C
cinelerra-5.0/cinelerra/cwindowgui.C
cinelerra-5.0/cinelerra/deleteallindexes.C
cinelerra-5.0/cinelerra/edl.C
cinelerra-5.0/cinelerra/ffmpeg.C
cinelerra-5.0/cinelerra/ffmpeg.h
cinelerra-5.0/cinelerra/fileac3.C
cinelerra-5.0/cinelerra/fileffmpeg.C
cinelerra-5.0/cinelerra/fileffmpeg.h
cinelerra-5.0/cinelerra/filempeg.C
cinelerra-5.0/cinelerra/filexml.C
cinelerra-5.0/cinelerra/filexml.h
cinelerra-5.0/cinelerra/indexable.C
cinelerra-5.0/cinelerra/indexable.h
cinelerra-5.0/cinelerra/indexfile.C
cinelerra-5.0/cinelerra/indexfile.h
cinelerra-5.0/cinelerra/indexfile.inc
cinelerra-5.0/cinelerra/indexstate.C
cinelerra-5.0/cinelerra/indexstate.h
cinelerra-5.0/cinelerra/indexstate.inc
cinelerra-5.0/cinelerra/indexthread.C
cinelerra-5.0/cinelerra/mbuttons.C
cinelerra-5.0/cinelerra/mediadb.C
cinelerra-5.0/cinelerra/mwindow.C
cinelerra-5.0/cinelerra/mwindowgui.C
cinelerra-5.0/cinelerra/nestededls.C
cinelerra-5.0/cinelerra/performanceprefs.C
cinelerra-5.0/cinelerra/performanceprefs.h
cinelerra-5.0/cinelerra/performanceprefs.inc
cinelerra-5.0/cinelerra/preferences.C
cinelerra-5.0/cinelerra/preferences.h
cinelerra-5.0/cinelerra/record.C
cinelerra-5.0/cinelerra/removefile.C
cinelerra-5.0/guicast/arraylist.h
cinelerra-5.0/guicast/bcwindowbase.C
cinelerra-5.0/guicast/test4.C
cinelerra-5.0/guicast/thread.C
cinelerra-5.0/guicast/thread.h

index c7ebcdd2ff939255bcb361cd1a207bf78ba471d7..42b5752a7e4df56b03691df235549e09c144e8f8 100644 (file)
@@ -201,12 +201,6 @@ void Asset::boundaries()
 //printf("Asset::boundaries %d %d %f\n", __LINE__, sample_rate, frame_rate);
 }
 
-
-void Asset::reset_index()
-{
-       index_state->reset();
-}
-
 void Asset::copy_from(Asset *asset, int do_index)
 {
        copy_location(asset);
@@ -574,11 +568,6 @@ int Asset::read_index(FileXML *file)
        return 0;
 }
 
-int Asset::write_index(const char *path, int data_bytes)
-{
-       return index_state->write_index(path, data_bytes, this, audio_length);
-}
-
 // Output path is the path of the output file if name truncation is desired.
 // It is a "" if complete names should be used.
 
@@ -723,7 +712,6 @@ int Asset::write_index(FileXML *file)
 
 
 
-
 const char* Asset::construct_param(const char *param, 
        const char *prefix, 
        char *return_value)
@@ -1034,18 +1022,6 @@ void Asset::save_defaults(BC_Hash *defaults,
 
 
 
-int Asset::update_path(char *new_path)
-{
-       strcpy(path, new_path);
-       return 0;
-}
-
-void Asset::update_index(Asset *asset)
-{
-       index_state->copy_from(asset->index_state);
-}
-
-
 int Asset::dump(FILE *fp)
 {
        fprintf(fp,"  asset::dump\n");
index 8fe38692f4910824840d397f8d49a888bcbb2b62..30523acdb7ae074927779ebd31ee619b56a56882 100644 (file)
@@ -30,6 +30,7 @@
 #include "filexml.inc"
 #include "indexable.h"
 #include "indexfile.inc"
+#include "indexstate.inc"
 #include "linklist.h"
 #include "pluginserver.inc"
 
@@ -79,7 +80,6 @@ public:
 
 
 // Executed during index building only
-       void update_index(Asset *asset);
        int equivalent(Asset &asset, 
                int test_audio, 
                int test_video);
@@ -96,17 +96,11 @@ public:
        int read_index(FileXML *xml);
        void reset_audio();
        void reset_video();
-       void reset_index();  // When the index file is wrong, reset the asset values
        int reset_timecode();
 
 // Output path is the path of the output file if name truncation is desired.
 // It is a "" if; complete names should be used.
-       int write(FileXML *file, 
-               int include_index, 
-               const char *output_path);
-// Write the index data and asset info.  Used by IndexThread.
-       int write_index(const char *path, int data_bytes);
-
+       int write(FileXML *file, int include_index, const char *output_path);
 
 // For Indexable
        int get_audio_channels();
@@ -126,7 +120,6 @@ public:
        int write_audio(FileXML *xml);
        int write_video(FileXML *xml);
        int write_index(FileXML *xml);
-       int update_path(char *new_path);
 
 
 
index 3ec41711984b42d174b436e695b4c8c553f3f5ac..60604d43619c85b4d9f67f92ef596e6c74e7982d 100644 (file)
@@ -524,6 +524,9 @@ int AudioALSA::write_buffer(char *buffer, int size)
                int ret = snd_pcm_avail_update(get_output());
                if( ret >= period_size ) {
                        if( ret > count ) ret = count;
+//FILE *alsa_fp = 0;
+//if( !alsa_fp ) alsa_fp = fopen("/tmp/alsa.raw","w");
+//if( alsa_fp ) fwrite(buffer, sample_size, ret, alsa_fp);
 //printf("AudioALSA::snd_pcm_writei start %d\n",count);
                        ret = snd_pcm_writei(get_output(),buffer,ret);
 //printf("AudioALSA::snd_pcm_writei done %d\n", ret);
index 704d24b2dba18648998d6d84856934fdc850b1b8..70df0cce36a7813a57a33ef7a4ddd334fcbbc86b 100644 (file)
@@ -113,6 +113,7 @@ AssetPicon::~AssetPicon()
        if(edl) edl->remove_user();
        if( icon && !gui->protected_pixmap(icon) ) {
                delete icon;
+               if( !plugin ) delete icon_vframe;
        }
 }
 
index 470d0b02850042940c6a2e35e5cbe697ae394017..95097523e26d62ddf3a7b96806312fed695dd171 100644 (file)
@@ -122,6 +122,7 @@ CWindowGUI::~CWindowGUI()
        delete zoom_panel;
        delete active;
        delete inactive;
+       delete orig_mask_keyframe;
 }
 
 void CWindowGUI::create_objects()
index 4160b1e6e485ab947585eca855f217ed2bde8a1c..4941e09368adf9e3e9087f76f53e9ed5e96f3b80 100644 (file)
@@ -68,6 +68,7 @@ void DeleteAllIndexes::run()
 // prepare filter
        const char *filter1 = ".idx";
        const char *filter2 = ".toc";
+       const char *filter3 = ".mkr";
 
 //     pwindow->disable_window();
        sprintf(string, _("Delete all indexes in %s?"), string1);
@@ -85,7 +86,8 @@ void DeleteAllIndexes::run()
                        sprintf(string2, "%s%s", string1, dir.dir_list.values[i]->name);
 // test filter
                        if(test_filter(string2, filter1) ||
-                               test_filter(string2, filter2))
+                               test_filter(string2, filter2) ||
+                               test_filter(string2, filter3))
                        {
                                remove(string2);
 printf("DeleteAllIndexes::run %s\n", string2);
index 05e7618cfdf26c98045716e5e84db3a5b9d9922a..8ef59f2bf984b1301dbf9bf02c5f6b5591b69c3c 100644 (file)
@@ -394,8 +394,7 @@ int EDL::save_xml(FileXML *file,
 int EDL::copy_all(EDL *edl)
 {
        if(this == edl) return 0;
-
-       index_state->copy_from(edl->index_state);
+       update_index(edl);
        nested_edls->clear();
        copy_session(edl);
        copy_assets(edl);
@@ -1201,7 +1200,7 @@ void EDL::insert_asset(Asset *asset,
 
 void EDL::set_index_file(Indexable *indexable)
 {
-       if(indexable->is_asset) 
+       if(indexable->is_asset)
                assets->update_index((Asset*)indexable);
        else
                nested_edls->update_index((EDL*)indexable);
index 2f1a1987cf6cd7fe6397da5ccb43381d4b82827d..efb11be359a0bc4018000ed7784b3ad1f2bb5385 100644 (file)
@@ -18,6 +18,7 @@
 #include "fileffmpeg.h"
 #include "file.h"
 #include "ffmpeg.h"
+#include "indexfile.h"
 #include "libdv.h"
 #include "libmjpeg.h"
 #include "mainerror.h"
@@ -97,35 +98,35 @@ int FFAudioStream::read(float *fp, long len)
        return len;
 }
 
-void FFAudioStream::realloc(long sz, int nch, long len)
+void FFAudioStream::realloc(long nsz, int nch, long len)
 {
-       long bsz = sz * nch;
+       long bsz = nsz * nch;
        float *np = new float[bsz];
        inp = np + read(np, len) * nch;
        outp = np;
        lmt = np + bsz;
        this->nch = nch;
-       this->sz = sz;
+       sz = nsz;
        delete [] bfr;  bfr = np;
 }
 
-void FFAudioStream::realloc(long sz, int nch)
+void FFAudioStream::realloc(long nsz, int nch)
 {
-       if( sz > this->sz || this->nch != nch ) {
-               long len = this->nch != nch ? 0 : curr_pos - seek_pos;
-               if( len > this->sz ) len = this->sz;
+       if( nsz > sz || this->nch != nch ) {
+               long len = this->nch != nch ? 0 : hpos;
+               if( len > sz ) len = sz;
                iseek(len);
-               realloc(sz, nch, len);
+               realloc(nsz, nch, len);
        }
 }
 
-void FFAudioStream::reserve(long sz, int nch)
+void FFAudioStream::reserve(long nsz, int nch)
 {
        long len = (inp - outp) / nch;
-       sz += len;
-       if( sz > this->sz || this->nch != nch ) {
+       nsz += len;
+       if( nsz > sz || this->nch != nch ) {
                if( this->nch != nch ) len = 0;
-               realloc(sz, nch, len);
+               realloc(nsz, nch, len);
                return;
        }
        if( (len*=nch) > 0 && bfr != outp )
@@ -146,9 +147,10 @@ long FFAudioStream::avail()
        long len = outp >= in1 ? outp-in1 : outp-bfr + lmt-in1;
        return len / nch;
 }
-void FFAudioStream::reset() // clear bfr
+void FFAudioStream::reset_history()
 {
        inp = outp = bfr;
+       hpos = 0;
 }
 
 void FFAudioStream::iseek(int64_t ofs)
@@ -182,6 +184,7 @@ int FFAudioStream::write(const float *fp, long len)
                if( ip >= lmt ) ip = bfr;
        }
        inp = ip;
+       hpos += len;
        return len;
 }
 
@@ -197,6 +200,7 @@ int FFAudioStream::zero(long len)
                if( ip >= lmt ) ip = bfr;
        }
        inp = ip;
+       hpos += len;
        return len;
 }
 
@@ -226,11 +230,11 @@ int FFAudioStream::write(const double *dp, long len, int ch)
 }
 
 
-FFStream::FFStream(FFMPEG *ffmpeg, AVStream *st, int idx)
+FFStream::FFStream(FFMPEG *ffmpeg, AVStream *st, int fidx)
 {
        this->ffmpeg = ffmpeg;
        this->st = st;
-       this->idx = idx;
+       this->fidx = fidx;
        frm_lock = new Mutex("FFStream::frm_lock");
        fmt_ctx = 0;
        filter_graph = 0;
@@ -238,10 +242,12 @@ FFStream::FFStream(FFMPEG *ffmpeg, AVStream *st, int idx)
        buffersink_ctx = 0;
        frm_count = 0;
        nudge = AV_NOPTS_VALUE;
-       eof = 0;
+       seek_pos = curr_pos = 0;
+       seeked = 1;  eof = 0;
+       index_markers = 0;
        reading = writing = 0;
-       need_packet = 1;
        flushed = 0;
+       need_packet = 1;
        frame = fframe = 0;
 }
 
@@ -303,7 +309,8 @@ int FFStream::decode_activate()
                ret = avformat_open_input(&fmt_ctx, ffmpeg->fmt_ctx->filename, NULL, &copts);
                if( ret >= 0 ) {
                        ret = avformat_find_stream_info(fmt_ctx, 0);
-                       st = fmt_ctx->streams[idx];
+                       st = fmt_ctx->streams[fidx];
+                       load_markers();
                }
                if( ret >= 0 ) {
                        AVCodecID codec_id = st->codec->codec_id;
@@ -326,35 +333,38 @@ int FFStream::read_packet()
 {
        av_packet_unref(ipkt);
        int ret = av_read_frame(fmt_ctx, ipkt);
-       if( ret >= 0 ) return 1;
-       st_eof(1);
-       if( ret == AVERROR_EOF ) return 0;
-       ff_err(ret, "FFStream::read_packet: av_read_frame failed\n");
-       flushed = 1;
-       return -1;
+       if( ret < 0 ) {
+               st_eof(1);
+               if( ret == AVERROR_EOF ) {
+                       ipkt->stream_index = st->index;
+                       return 0;
+               }
+               ff_err(ret, "FFStream::read_packet: av_read_frame failed\n");
+               flushed = 1;
+               return -1;
+       }
+       return 1;
 }
 
 int FFStream::decode(AVFrame *frame)
 {
        int ret = 0;
-       int retries = 100;
+       int retries = 1000;
        int got_frame = 0;
 
        while( ret >= 0 && !flushed && --retries >= 0 && !got_frame ) {
                if( need_packet ) {
                        need_packet = 0;
-                       ret = read_packet();
-                       if( ret < 0 ) break;
-                       if( !ret ) ipkt->stream_index = st->index;
+                       if( (ret=read_packet()) < 0 ) break;
                }
                if( ipkt->stream_index == st->index ) {
                        while( (ipkt->size > 0 || !ipkt->data) && !got_frame ) {
-                               ret = decode_frame(frame, got_frame);
-                               if( ret < 0 || !ipkt->data ) break;
+                               ret = decode_frame(ipkt, frame, got_frame);
+                               if( ret <= 0 || !ipkt->data ) break;
                                ipkt->data += ret;
                                ipkt->size -= ret;
                        }
-                       retries = 100;
+                       retries = 1000;
                }
                if( !got_frame ) {
                        need_packet = 1;
@@ -434,13 +444,57 @@ int FFStream::flush()
        return ret >= 0 ? 0 : 1;
 }
 
-FFAudioStream::FFAudioStream(FFMPEG *ffmpeg, AVStream *strm, int idx)
- : FFStream(ffmpeg, strm, idx)
+int FFStream::seek(int64_t no, double rate)
+{
+       if( no < 0 ) no = 0;
+// default ffmpeg native seek
+       int npkts = 1;
+       int64_t pos = no, plmt = -1;
+       if( index_markers && index_markers->size() > 1 ) {
+               IndexMarks &marks = *index_markers;
+               int i = marks.find(pos);
+               int64_t n = i < 0 ? (i=0) : marks[i].no;
+// if indexed seek point not too far away (<30 secs), use index
+               if( no-n < 30*rate ) {
+                       if( n < 0 ) n = 0;
+                       pos = n;
+                       plmt = marks[i].pos;
+                       npkts = 1000;
+               }
+       }
+       double secs = pos / rate;
+       int64_t tstmp = secs * st->time_base.den / st->time_base.num;
+       if( nudge != AV_NOPTS_VALUE ) tstmp += nudge;
+       if( avformat_seek_file(fmt_ctx, st->index,
+               -INT64_MAX, tstmp, INT64_MAX, AVSEEK_FLAG_ANY) < 0 ) return -1;
+       avcodec_flush_buffers(st->codec);
+       need_packet = 0;  flushed = 0;
+       seeked = 1;  st_eof(0);
+       int64_t pkt_ts = AV_NOPTS_VALUE;
+       int ret = 1, retry = 1000;
+
+// read up to retry packets, limited to npkts in stream, and not past pkt.pos plmt
+       while( ret > 0 && npkts > 0 && --retry >= 0 ) {
+               if( (ret=read_packet()) <= 0 ) break;
+               if( ipkt->stream_index != st->index ) continue;
+               if( (pkt_ts=ipkt->dts) == AV_NOPTS_VALUE ) pkt_ts = ipkt->pts;
+               if( pkt_ts != AV_NOPTS_VALUE && pkt_ts >= tstmp ) break;
+               if( plmt >= 0 && ipkt->pos >= plmt ) break;
+               --npkts;
+       }
+
+       if( ret <= 0 || retry < 0 ) return -1;
+       seek_pos = curr_pos = pos;
+       return npkts > 0 ? 1 : 0;
+}
+
+FFAudioStream::FFAudioStream(FFMPEG *ffmpeg, AVStream *strm, int idx, int fidx)
+ : FFStream(ffmpeg, strm, fidx)
 {
+       this->idx = idx;
        channel0 = channels = 0;
        sample_rate = 0;
        mbsz = 0;
-       seek_pos = curr_pos = 0;
        length = 0;
        resample_context = 0;
 
@@ -452,8 +506,8 @@ FFAudioStream::FFAudioStream(FFMPEG *ffmpeg, AVStream *strm, int idx)
        sz = 0x10000;
        long bsz = sz * nch;
        bfr = new float[bsz];
-       inp = outp = bfr;
        lmt = bfr + bsz;
+       reset_history();
 }
 
 FFAudioStream::~FFAudioStream()
@@ -463,9 +517,9 @@ FFAudioStream::~FFAudioStream()
        delete [] bfr;
 }
 
-int FFAudioStream::load_history(uint8_t **data, int len)
+int FFAudioStream::get_samples(float *&samples, uint8_t **data, int len)
 {
-       float *samples = *(float **)data;
+       samples = *(float **)data;
        if( resample_context ) {
                if( len > aud_bfr_sz ) {        
                        delete [] aud_bfr;
@@ -478,25 +532,41 @@ int FFAudioStream::load_history(uint8_t **data, int len)
                int ret = swr_convert(resample_context,
                        (uint8_t**)&aud_bfr, aud_bfr_sz, (const uint8_t**)data, len);
                if( ret < 0 ) {
-                       ff_err(ret, "FFAudioStream::load_history: swr_convert failed\n");
+                       ff_err(ret, "FFAudioStream::get_samples: swr_convert failed\n");
                        return -1;
                }
                samples = aud_bfr;
                len = ret;
        }
-       // biggest user bfr since seek + frame
-       realloc(mbsz + len + 1, channels);
-       write(samples, len);
        return len;
 }
 
-int FFAudioStream::decode_frame(AVFrame *frame, int &got_frame)
+int FFAudioStream::load_history(uint8_t **data, int len)
 {
-       int ret = avcodec_decode_audio4(st->codec, frame, &got_frame, ipkt);
+       float *samples;
+       len = get_samples(samples, data, len);
+       if( len > 0 ) {
+               // biggest user bfr since seek + frame
+               realloc(mbsz + len + 1, channels);
+               write(samples, len);
+       }
+       return len;
+}
+
+int FFAudioStream::decode_frame(AVPacket *pkt, AVFrame *frame, int &got_frame)
+{
+       int first_frame = seeked;  seeked = 0;
+       int ret = avcodec_decode_audio4(st->codec, frame, &got_frame, pkt);
        if( ret < 0 ) {
+               if( first_frame ) return 0;
                ff_err(ret, "FFAudioStream::decode_frame: Could not read audio frame\n");
                return -1;
        }
+       if( got_frame ) {
+               int64_t pkt_ts = av_frame_get_best_effort_timestamp(frame);
+               if( pkt_ts != AV_NOPTS_VALUE )
+                       curr_pos = ffmpeg->to_secs(pkt_ts - nudge, st->time_base) * sample_rate + 0.5;
+       }
        return ret;
 }
 
@@ -513,7 +583,7 @@ int FFAudioStream::nb_samples()
 {
        AVCodecContext *ctx = st->codec;
        return ctx->codec->capabilities & CODEC_CAP_VARIABLE_FRAME_SIZE ?
-                10000 : ctx->frame_size;
+               10000 : ctx->frame_size;
 }
 
 int64_t FFAudioStream::load_buffer(double ** const sp, int len)
@@ -527,7 +597,7 @@ int64_t FFAudioStream::load_buffer(double ** const sp, int len)
 int FFAudioStream::in_history(int64_t pos)
 {
        if( pos > curr_pos ) return 0;
-       int64_t len = curr_pos - seek_pos;
+       int64_t len = hpos;
        if( len > sz ) len = sz;
        if( pos < curr_pos - len ) return 0;
        return 1;
@@ -550,13 +620,13 @@ int FFAudioStream::init_frame(AVFrame *frame)
 int FFAudioStream::load(int64_t pos, int len)
 {
        if( audio_seek(pos) < 0 ) return -1;
-       if( mbsz < len ) mbsz = len;
-       int ret = 0;
-       int64_t end_pos = pos + len;
        if( !frame && !(frame=av_frame_alloc()) ) {
                fprintf(stderr, "FFAudioStream::load: av_frame_alloc failed\n");
                return -1;
        }
+       if( mbsz < len ) mbsz = len;
+       int64_t end_pos = pos + len;
+       int ret = 0;
        for( int i=0; ret>=0 && !flushed && curr_pos<end_pos && i<1000; ++i ) {
                ret = read_frame(frame);
                if( ret > 0 ) {
@@ -568,26 +638,20 @@ int FFAudioStream::load(int64_t pos, int len)
                zero(end_pos - curr_pos);
                curr_pos = end_pos;
        }
-       return curr_pos - pos;
+       len = curr_pos - pos;
+       iseek(len);
+       return len;
 }
 
 int FFAudioStream::audio_seek(int64_t pos)
 {
        if( decode_activate() < 0 ) return -1;
-       if( in_history(pos) ) {
-               iseek(curr_pos - pos);
-               return 0;
-       }
-       if( pos == curr_pos ) return 0;
        if( !st->codec || !st->codec->codec ) return -1;
-       avcodec_flush_buffers(st->codec);
-       double secs = (double)pos / sample_rate;
-       int64_t tstmp = secs * st->time_base.den / st->time_base.num;
-       if( nudge != AV_NOPTS_VALUE ) tstmp += nudge;
-       avformat_seek_file(fmt_ctx, st->index, -INT64_MAX, tstmp, INT64_MAX, 0);
-       seek_pos = curr_pos = pos;
-       reset();  st_eof(0);
-       mbsz = 0; flushed = 0;  need_packet = 1;
+       if( in_history(pos) ) return 0;
+       if( pos == curr_pos ) return 0;
+       reset_history();  mbsz = 0;
+// guarentee preload > 1sec samples
+       if( seek(pos-sample_rate, sample_rate) < 0 ) return -1;
        return 1;
 }
 
@@ -621,7 +685,7 @@ int FFAudioStream::encode(double **samples, int len)
        return ret >= 0 ? 0 : 1;
 }
 
-int FFAudioStream::encode_frame(FFPacket &pkt, AVFrame *frame, int &got_packet)
+int FFAudioStream::encode_frame(AVPacket *pkt, AVFrame *frame, int &got_packet)
 {
        int ret = avcodec_encode_audio2(st->codec, pkt, frame, &got_packet);
        if( ret < 0 ) {
@@ -631,13 +695,20 @@ int FFAudioStream::encode_frame(FFPacket &pkt, AVFrame *frame, int &got_packet)
        return ret;
 }
 
-FFVideoStream::FFVideoStream(FFMPEG *ffmpeg, AVStream *strm, int idx)
- : FFStream(ffmpeg, strm, idx)
+void FFAudioStream::load_markers()
+{
+       IndexState *index_state = ffmpeg->file_base->asset->index_state;
+       if( !index_state || idx >= index_state->audio_markers.size() ) return;
+       FFStream::load_markers(*index_state->audio_markers[idx], sample_rate);
+}
+
+FFVideoStream::FFVideoStream(FFMPEG *ffmpeg, AVStream *strm, int idx, int fidx)
+ : FFStream(ffmpeg, strm, fidx)
 {
+       this->idx = idx;
        width = height = 0;
        frame_rate = 0;
        aspect_ratio = 0;
-       seek_pos = curr_pos = 0;
        length = 0;
        convert_ctx = 0;
 }
@@ -647,15 +718,20 @@ FFVideoStream::~FFVideoStream()
        if( convert_ctx ) sws_freeContext(convert_ctx);
 }
 
-int FFVideoStream::decode_frame(AVFrame *frame, int &got_frame)
+int FFVideoStream::decode_frame(AVPacket *pkt, AVFrame *frame, int &got_frame)
 {
-       int ret = avcodec_decode_video2(st->codec, frame, &got_frame, ipkt);
+       int first_frame = seeked;  seeked = 0;
+       int ret = avcodec_decode_video2(st->codec, frame, &got_frame, pkt);
        if( ret < 0 ) {
+               if( first_frame ) return 0;
                ff_err(ret, "FFVideoStream::decode_frame: Could not read video frame\n");
                return -1;
        }
-       if( got_frame )
-               ++curr_pos;
+       if( got_frame ) {
+               int64_t pkt_ts = av_frame_get_best_effort_timestamp(frame);
+               if( pkt_ts != AV_NOPTS_VALUE )
+                       curr_pos = ffmpeg->to_secs(pkt_ts - nudge, st->time_base) * frame_rate + 0.5;
+       }
        return ret;
 }
 
@@ -669,6 +745,7 @@ int FFVideoStream::load(VFrame *vframe, int64_t pos)
        }
        for( int i=0; ret>=0 && !flushed && curr_pos<=pos && i<1000; ++i ) {
                ret = read_frame(frame);
+               if( ret > 0 ) ++curr_pos;
        }
        if( ret > 0 ) {
                AVCodecContext *ctx = st->codec;
@@ -682,24 +759,16 @@ int FFVideoStream::load(VFrame *vframe, int64_t pos)
 int FFVideoStream::video_seek(int64_t pos)
 {
        if( decode_activate() < 0 ) return -1;
+       if( !st->codec || !st->codec->codec ) return -1;
+       if( pos == curr_pos-1 && !seeked ) return 0;
 // if close enough, just read up to current
-//   3*gop_size seems excessive, but less causes tears
-       int gop = 3*st->codec->gop_size;
+       int gop = st->codec->gop_size;
        if( gop < 4 ) gop = 4;
        if( gop > 64 ) gop = 64;
-       if( pos >= curr_pos && pos <= curr_pos + gop ) return 0;
-       if( pos == curr_pos-1 && curr_pos > seek_pos ) return 1;
-       if( !st->codec || !st->codec->codec ) return -1;
-       avcodec_flush_buffers(st->codec);
-// back up a few frames to read up to current to help repair damages
-       if( (pos-=gop) < 0 ) pos = 0;
-       double secs = (double)pos / frame_rate;
-       int64_t tstmp = secs * st->time_base.den / st->time_base.num;
-       if( nudge != AV_NOPTS_VALUE ) tstmp += nudge;
-       avformat_seek_file(fmt_ctx, st->index, -INT64_MAX, tstmp, INT64_MAX, 0);
-       seek_pos = curr_pos = pos;
-       st_eof(0);
-       flushed = 0;  need_packet = 1;
+       int read_limit = curr_pos + 3*gop;
+       if( pos >= curr_pos && pos <= read_limit ) return 0;
+// guarentee preload more than 2*gop frames
+       if( seek(pos - 3*gop, frame_rate) < 0 ) return -1;
        return 1;
 }
 
@@ -737,7 +806,7 @@ int FFVideoStream::encode(VFrame *vframe)
        return ret >= 0 ? 0 : 1;
 }
 
-int FFVideoStream::encode_frame(FFPacket &pkt, AVFrame *frame, int &got_packet)
+int FFVideoStream::encode_frame(AVPacket *pkt, AVFrame *frame, int &got_packet)
 {
        int ret = avcodec_encode_video2(st->codec, pkt, frame, &got_packet);
        if( ret < 0 ) {
@@ -911,6 +980,13 @@ int FFVideoStream::convert_pixfmt(VFrame *frame,
        return 0;
 }
 
+void FFVideoStream::load_markers()
+{
+       IndexState *index_state = ffmpeg->file_base->asset->index_state;
+       if( idx >= index_state->video_markers.size() ) return;
+       FFStream::load_markers(*index_state->video_markers[idx], frame_rate);
+}
+
 
 FFMPEG::FFMPEG(FileBase *file_base)
 {
@@ -938,7 +1014,7 @@ FFMPEG::~FFMPEG()
        close_encoder();
        ffaudio.remove_all_objects();
        ffvideo.remove_all_objects();
-       if( encoding ) avformat_free_context(fmt_ctx);
+       if( fmt_ctx ) avformat_close_input(&fmt_ctx);
        ff_unlock();
        delete flow_lock;
        delete mux_lock;
@@ -1216,51 +1292,76 @@ double FFMPEG::to_secs(int64_t time, AVRational time_base)
 int FFMPEG::info(char *text, int len)
 {
        if( len <= 0 ) return 0;
+       decode_activate();
 #define report(s...) do { int n = snprintf(cp,len,s); cp += n;  len -= n; } while(0)
        char *cp = text;
-       for( int i=0; i<(int)fmt_ctx->nb_streams; ++i ) {
-               AVStream *st = fmt_ctx->streams[i];
+       if( ffvideo.size() > 0 )
+               report("\n%d video stream%s\n",ffvideo.size(), ffvideo.size()!=1 ? "s" : "");
+       for( int vidx=0; vidx<ffvideo.size(); ++vidx ) {
+               FFVideoStream *vid = ffvideo[vidx];
+               AVStream *st = vid->st;
                AVCodecContext *avctx = st->codec;
-               report(_("stream %d,  id 0x%06x:\n"), i, avctx->codec_id);
+               report(_("vid%d (%d),  id 0x%06x:\n"), vid->idx, vid->fidx, avctx->codec_id);
                const AVCodecDescriptor *desc = avcodec_descriptor_get(avctx->codec_id);
-               if( avctx->codec_type == AVMEDIA_TYPE_VIDEO ) {
-                       AVRational framerate = av_guess_frame_rate(fmt_ctx, st, 0);
-                       double frame_rate = !framerate.den ? 0 : (double)framerate.num / framerate.den;
-                       report("  video %s",desc ? desc->name : " (unkn)");
-                       report(" %dx%d %5.2f", avctx->width, avctx->height, frame_rate);
-                       const char *pfn = av_get_pix_fmt_name(avctx->pix_fmt);
-                       report(" pix %s\n", pfn ? pfn : "(unkn)");
-                       double secs = to_secs(st->duration, st->time_base);
-                       int64_t length = secs * frame_rate + 0.5;
-                       report("    %jd frms %0.2f secs", length, secs);
-                       int hrs = secs/3600;  secs -= hrs*3600;
-                       int mins = secs/60;  secs -= mins*60;
-                       report("  %d:%02d:%05.2f\n", hrs, mins, secs);
-
-               }
-               else if( avctx->codec_type == AVMEDIA_TYPE_AUDIO ) {
-                       int sample_rate = avctx->sample_rate;
-                       const char *fmt = av_get_sample_fmt_name(avctx->sample_fmt);
-                       report("  audio %s",desc ? desc->name : " (unkn)");
-                       report(" %dch %s %d",avctx->channels, fmt, sample_rate);
-                       int sample_bits = av_get_bits_per_sample(avctx->codec_id);
-                       report(" %dbits\n", sample_bits);
-                       double secs = to_secs(st->duration, st->time_base);
-                       int64_t length = secs * sample_rate + 0.5;
-                       report("    %jd smpl %0.2f secs", length, secs);
-                       int hrs = secs/3600;  secs -= hrs*3600;
-                       int mins = secs/60;  secs -= mins*60;
-                       report("  %d:%02d:%05.2f\n", hrs, mins, secs);
-               }
-               else
-                       report(_("  codec_type unknown\n"));
-       }
-       report("\n");
+               report("  video%d %s", vidx+1, desc ? desc->name : " (unkn)");
+               report(" %dx%d %5.2f", vid->width, vid->height, vid->frame_rate);
+               const char *pfn = av_get_pix_fmt_name(avctx->pix_fmt);
+               report(" pix %s\n", pfn ? pfn : "(unkn)");
+               double secs = to_secs(st->duration, st->time_base);
+               int64_t length = secs * vid->frame_rate + 0.5;
+               double ofs = to_secs((vid->nudge - st->start_time), st->time_base);
+               int64_t nudge = ofs * vid->frame_rate;
+               int ch = nudge >= 0 ? '+' : (nudge=-nudge, '-');
+               report("    %jd%c%jd frms %0.2f secs", length,ch,nudge, secs);
+               int hrs = secs/3600;  secs -= hrs*3600;
+               int mins = secs/60;  secs -= mins*60;
+               report("  %d:%02d:%05.2f\n", hrs, mins, secs);
+       }
+       if( ffaudio.size() > 0 )
+               report("\n%d audio stream%s\n",ffaudio.size(), ffaudio.size()!=1 ? "s" : "");
+       for( int aidx=0; aidx<ffaudio.size(); ++aidx ) {
+               FFAudioStream *aud = ffaudio[aidx];
+               AVStream *st = aud->st;
+               AVCodecContext *avctx = st->codec;
+               report(_("aud%d (%d),  id 0x%06x:\n"), aud->idx, aud->fidx, avctx->codec_id);
+               const AVCodecDescriptor *desc = avcodec_descriptor_get(avctx->codec_id);
+               int nch = aud->channels, ch0 = aud->channel0+1;
+               report("  audio%d-%d %s", ch0, ch0+nch-1, desc ? desc->name : " (unkn)");
+               const char *fmt = av_get_sample_fmt_name(avctx->sample_fmt);
+               report(" %s %d", fmt, aud->sample_rate);
+               int sample_bits = av_get_bits_per_sample(avctx->codec_id);
+               report(" %dbits\n", sample_bits);
+               double secs = to_secs(st->duration, st->time_base);
+               int64_t length = secs * aud->sample_rate + 0.5;
+               double ofs = to_secs((aud->nudge - st->start_time), st->time_base);
+               int64_t nudge = ofs * aud->sample_rate;
+               int ch = nudge >= 0 ? '+' : (nudge=-nudge, '-');
+               report("    %jd%c%jd smpl %0.2f secs", length,ch,nudge, secs);
+               int hrs = secs/3600;  secs -= hrs*3600;
+               int mins = secs/60;  secs -= mins*60;
+               report("  %d:%02d:%05.2f\n", hrs, mins, secs);
+       }
+       if( fmt_ctx->nb_programs > 0 )
+               report("\n%d program%s\n",fmt_ctx->nb_programs, fmt_ctx->nb_programs!=1 ? "s" : "");
        for( int i=0; i<(int)fmt_ctx->nb_programs; ++i ) {
                report("program %d", i+1);
                AVProgram *pgrm = fmt_ctx->programs[i];
-               for( int j=0; j<(int)pgrm->nb_stream_indexes; ++j )
-                       report(", %d", pgrm->stream_index[j]);
+               for( int j=0; j<(int)pgrm->nb_stream_indexes; ++j ) {
+                       int idx = pgrm->stream_index[j];
+                       int vidx = ffvideo.size();
+                       while( --vidx>=0 && ffvideo[vidx]->fidx != idx );
+                       if( vidx >= 0 ) {
+                               report(", vid%d", vidx);
+                               continue;
+                       }
+                       int aidx = ffaudio.size();
+                       while( --aidx>=0 && ffaudio[aidx]->fidx != idx );
+                       if( aidx >= 0 ) {
+                               report(", aud%d", aidx);
+                               continue;
+                       }
+                       report(", (%d)", pgrm->stream_index[j]);
+               }
                report("\n");
        }
        report("\n");
@@ -1347,8 +1448,8 @@ int FFMPEG::open_decoder()
                        AVRational framerate = av_guess_frame_rate(fmt_ctx, st, 0);
                        if( framerate.num < 1 ) continue;
                        has_video = 1;
-                       FFVideoStream *vid = new FFVideoStream(this, st, i);
                        int vidx = ffvideo.size();
+                       FFVideoStream *vid = new FFVideoStream(this, st, vidx, i);
                        vstrm_index.append(ffidx(vidx, 0));
                        ffvideo.append(vid);
                        vid->width = avctx->width;
@@ -1366,8 +1467,8 @@ int FFMPEG::open_decoder()
                        if( avctx->channels < 1 ) continue;
                        if( avctx->sample_rate < 1 ) continue;
                        has_audio = 1;
-                       FFAudioStream *aud = new FFAudioStream(this, st, i);
                        int aidx = ffaudio.size();
+                       FFAudioStream *aud = new FFAudioStream(this, st, aidx, i);
                        ffaudio.append(aud);
                        aud->channel0 = astrm_index.size();
                        aud->channels = avctx->channels;
@@ -1507,8 +1608,8 @@ int FFMPEG::open_encoder(const char *type, const char *spec)
                                av_dict_set(&sopts, "b", arg, 0);
                        }
                        int aidx = ffaudio.size();
-                       int idx = aidx + ffvideo.size();
-                       FFAudioStream *aud = new FFAudioStream(this, st, idx);
+                       int fidx = aidx + ffvideo.size();
+                       FFAudioStream *aud = new FFAudioStream(this, st, aidx, fidx);
                        ffaudio.append(aud);  fst = aud;
                        aud->sample_rate = asset->sample_rate;
                        ctx->channels = aud->channels = asset->channels;
@@ -1566,8 +1667,8 @@ int FFMPEG::open_encoder(const char *type, const char *spec)
                                av_dict_set(&sopts, "global_quality", arg, 0);
                        }
                        int vidx = ffvideo.size();
-                       int idx = vidx + ffaudio.size();
-                       FFVideoStream *vid = new FFVideoStream(this, st, idx);
+                       int fidx = vidx + ffaudio.size();
+                       FFVideoStream *vid = new FFVideoStream(this, st, vidx, fidx);
                        vstrm_index.append(ffidx(vidx, 0));
                        ffvideo.append(vid);  fst = vid;
                        vid->width = asset->width;
@@ -1634,80 +1735,89 @@ int FFMPEG::decode_activate()
 {
        if( decoding < 0 ) {
                decoding = 0;
+               for( int vidx=0; vidx<ffvideo.size(); ++vidx )
+                       ffvideo[vidx]->nudge = AV_NOPTS_VALUE;
+               for( int aidx=0; aidx<ffaudio.size(); ++aidx )
+                       ffaudio[aidx]->nudge = AV_NOPTS_VALUE;
+               // set nudges for each program stream set
                int npgrms = fmt_ctx->nb_programs;
                for( int i=0; i<npgrms; ++i ) {
                        AVProgram *pgrm = fmt_ctx->programs[i];
                        // first start time video stream
-                       int64_t vstart_time = -1;
+                       int64_t vstart_time = -1, astart_time = -1;
                        for( int j=0; j<(int)pgrm->nb_stream_indexes; ++j ) {
-                               int st_idx = pgrm->stream_index[j];
-                               AVStream *st = fmt_ctx->streams[st_idx];
+                               int fidx = pgrm->stream_index[j];
+                               AVStream *st = fmt_ctx->streams[fidx];
                                AVCodecContext *avctx = st->codec;
                                if( avctx->codec_type == AVMEDIA_TYPE_VIDEO ) {
                                        if( st->start_time == AV_NOPTS_VALUE ) continue;
+                                       if( vstart_time > st->start_time ) continue;
                                        vstart_time = st->start_time;
-                                       break;
+                                       continue;
                                }
-                       }
-                       // max start time audio stream
-                       int64_t astart_time = -1;
-                       for( int j=0; j<(int)pgrm->nb_stream_indexes; ++j ) {
-                               int st_idx = pgrm->stream_index[j];
-                               AVStream *st = fmt_ctx->streams[st_idx];
-                               AVCodecContext *avctx = st->codec;
                                if( avctx->codec_type == AVMEDIA_TYPE_VIDEO ) {
                                        if( st->start_time == AV_NOPTS_VALUE ) continue;
                                        if( astart_time > st->start_time ) continue;
                                        astart_time = st->start_time;
+                                       continue;
                                }
                        }
-                       if( astart_time < 0 || vstart_time < 0 ) continue;
                        // match program streams to max start_time
                        int64_t nudge = vstart_time > astart_time ? vstart_time : astart_time;
                        for( int j=0; j<(int)pgrm->nb_stream_indexes; ++j ) {
-                               int st_idx = pgrm->stream_index[j];
-                               AVStream *st = fmt_ctx->streams[st_idx];
+                               int fidx = pgrm->stream_index[j];
+                               AVStream *st = fmt_ctx->streams[fidx];
                                AVCodecContext *avctx = st->codec;
-                               if( avctx->codec_type == AVMEDIA_TYPE_AUDIO ) {
-                                       for( int k=0; k<ffaudio.size(); ++k ) {
-                                               if( ffaudio[k]->idx == st_idx )
-                                                       ffaudio[k]->nudge = nudge;
+                               if( avctx->codec_type == AVMEDIA_TYPE_VIDEO ) {
+                                       for( int k=0; k<ffvideo.size(); ++k ) {
+                                               if( ffvideo[k]->fidx != fidx ) continue;
+                                               ffvideo[k]->nudge = nudge;
                                        }
+                                       continue;
                                }
-                               else if( avctx->codec_type == AVMEDIA_TYPE_VIDEO ) {
-                                       for( int k=0; k<ffvideo.size(); ++k ) {
-                                               if( ffvideo[k]->idx == st_idx )
-                                                       ffvideo[k]->nudge = nudge;
+                               if( avctx->codec_type == AVMEDIA_TYPE_AUDIO ) {
+                                       for( int k=0; k<ffaudio.size(); ++k ) {
+                                               if( ffaudio[k]->fidx != fidx ) continue;
+                                               ffaudio[k]->nudge = nudge;
                                        }
+                                       continue;
                                }
                        }
                }
+               // set nudges for any streams not yet set
                int64_t vstart_time = 0, astart_time = 0;
                int nstreams = fmt_ctx->nb_streams;
                for( int i=0; i<nstreams; ++i ) {
                        AVStream *st = fmt_ctx->streams[i];
                        AVCodecContext *avctx = st->codec;
                        switch( avctx->codec_type ) {
-                       case AVMEDIA_TYPE_VIDEO:
+                       case AVMEDIA_TYPE_VIDEO: {
                                if( st->start_time == AV_NOPTS_VALUE ) continue;
+                               int vidx = ffvideo.size();
+                               while( --vidx >= 0 && ffvideo[vidx]->fidx != i );
+                               if( vidx >= 0 && ffvideo[vidx]->nudge != AV_NOPTS_VALUE ) continue;
                                if( vstart_time >= st->start_time ) continue;
                                vstart_time = st->start_time;
-                               break;
-                       case AVMEDIA_TYPE_AUDIO:
+                               break; }
+                       case AVMEDIA_TYPE_AUDIO: {
                                if( st->start_time == AV_NOPTS_VALUE ) continue;
+                               int aidx = ffaudio.size();
+                               while( --aidx >= 0 && ffaudio[aidx]->fidx != i );
+                               if( aidx >= 0 && ffaudio[aidx]->nudge != AV_NOPTS_VALUE ) continue;
                                if( astart_time >= st->start_time ) continue;
                                astart_time = st->start_time;
+                               break; }
                        default: break;
                        }
                }
                int64_t nudge = vstart_time > astart_time ? vstart_time : astart_time;
-               for( int k=0; k<ffvideo.size(); ++k ) {
-                       if( ffvideo[k]->nudge != AV_NOPTS_VALUE ) continue;
-                       ffvideo[k]->nudge = nudge;
+               for( int vidx=0; vidx<ffvideo.size(); ++vidx ) {
+                       if( ffvideo[vidx]->nudge != AV_NOPTS_VALUE ) continue;
+                       ffvideo[vidx]->nudge = nudge;
                }
-               for( int k=0; k<ffaudio.size(); ++k ) {
-                       if( ffaudio[k]->nudge != AV_NOPTS_VALUE ) continue;
-                       ffaudio[k]->nudge = nudge;
+               for( int aidx=0; aidx<ffaudio.size(); ++aidx ) {
+                       if( ffaudio[aidx]->nudge != AV_NOPTS_VALUE ) continue;
+                       ffaudio[aidx]->nudge = nudge;
                }
                decoding = 1;
        }
@@ -1742,12 +1852,13 @@ int FFMPEG::encode_activate()
        return encoding;
 }
 
+
 int FFMPEG::audio_seek(int stream, int64_t pos)
 {
        int aidx = astrm_index[stream].st_idx;
        FFAudioStream *aud = ffaudio[aidx];
+       pos = pos * aud->sample_rate / file_base->asset->sample_rate + 0.5;
        aud->audio_seek(pos);
-       aud->seek_pos = aud->curr_pos = pos;
        return 0;
 }
 
@@ -1755,8 +1866,8 @@ int FFMPEG::video_seek(int stream, int64_t pos)
 {
        int vidx = vstrm_index[stream].st_idx;
        FFVideoStream *vid = ffvideo[vidx];
+       pos = pos * vid->frame_rate / file_base->asset->frame_rate + 0.5;
        vid->video_seek(pos);
-       vid->seek_pos = vid->curr_pos = pos;
        return 0;
 }
 
@@ -1766,9 +1877,11 @@ int FFMPEG::decode(int chn, int64_t pos, double *samples, int len)
        if( !has_audio || chn >= astrm_index.size() ) return -1;
        int aidx = astrm_index[chn].st_idx;
        FFAudioStream *aud = ffaudio[aidx];
+       pos = pos * aud->sample_rate / file_base->asset->sample_rate + 0.5;
        if( aud->load(pos, len) < len ) return -1;
        int ch = astrm_index[chn].st_ch;
-       return aud->read(samples,len,ch);
+       int ret = aud->read(samples,len,ch);
+       return ret;
 }
 
 int FFMPEG::decode(int layer, int64_t pos, VFrame *vframe)
@@ -1776,9 +1889,11 @@ int FFMPEG::decode(int layer, int64_t pos, VFrame *vframe)
        if( !has_video || layer >= vstrm_index.size() ) return -1;
        int vidx = vstrm_index[layer].st_idx;
        FFVideoStream *vid = ffvideo[vidx];
+       pos = pos * vid->frame_rate / file_base->asset->frame_rate + 0.5;
        return vid->load(vframe, pos);
 }
 
+
 int FFMPEG::encode(int stream, double **samples, int len)
 {
        FFAudioStream *aud = ffaudio[stream];
@@ -1967,7 +2082,7 @@ int FFMPEG::ff_audio_for_video(int vstream, int astream, int64_t &channel_mask)
 {
        channel_mask = 0;
        int pidx = -1;
-       int vidx = ffvideo[vstream]->idx;
+       int vidx = ffvideo[vstream]->fidx;
        // find first program with this video stream
        for( int i=0; pidx<0 && i<(int)fmt_ctx->nb_programs; ++i ) {
                AVProgram *pgrm = fmt_ctx->programs[i];
@@ -1989,7 +2104,7 @@ int FFMPEG::ff_audio_for_video(int vstream, int astream, int64_t &channel_mask)
                if( astream > 0 ) { --astream;  continue; }
                int astrm = -1;
                for( int i=0; astrm<0 && i<ffaudio.size(); ++i )
-                       if( ffaudio[i]->idx == aidx ) astrm = i;
+                       if( ffaudio[i]->fidx == aidx ) astrm = i;
                if( astrm >= 0 ) {
                        if( ret < 0 ) ret = astrm;
                        int64_t mask = (1 << ffaudio[astrm]->channels) - 1;
@@ -2229,3 +2344,148 @@ int FFStream::bs_filter(AVPacket *pkt)
        return ret;
 }
 
+int FFMPEG::scan(IndexState *index_state, int64_t *scan_position, int *canceled)
+{
+       AVPacket pkt;
+       av_init_packet(&pkt);
+       AVFrame *frame = av_frame_alloc();
+       if( !frame ) {
+               fprintf(stderr, "FFMPEG::scan: av_frame_alloc failed\n");
+               return -1;
+       }
+
+       index_state->add_video_markers(ffvideo.size());
+       index_state->add_audio_markers(ffaudio.size());
+
+       for( int i=0; i<(int)fmt_ctx->nb_streams; ++i ) {
+               AVDictionary *copts = 0;
+               av_dict_copy(&copts, opts, 0);
+               AVStream *st = fmt_ctx->streams[i];
+               AVCodecID codec_id = st->codec->codec_id;
+               AVCodec *decoder = avcodec_find_decoder(codec_id);
+               if( avcodec_open2(st->codec, decoder, &copts) < 0 )
+                       fprintf(stderr, "FFMPEG::scan: codec open failed\n");
+               av_dict_free(&copts);
+       }
+       int errs = 0;
+       for( int64_t count=0; !*canceled; ++count ) {
+               av_packet_unref(&pkt);
+               pkt.data = 0; pkt.size = 0;
+
+               int ret = av_read_frame(fmt_ctx, &pkt);
+               if( ret < 0 ) {
+                       if( ret == AVERROR_EOF ) break;
+                       if( ++errs > 100 ) {
+                               ff_err(ret, "over 100 read_frame errs\n");
+                               break;
+                       }
+                       continue;
+               }
+               if( !pkt.data ) continue;
+               int i = pkt.stream_index;
+               if( i < 0 || i >= (int)fmt_ctx->nb_streams ) continue;
+               AVStream *st = fmt_ctx->streams[i];
+               AVCodecContext *avctx = st->codec;
+               if( pkt.pos > *scan_position ) *scan_position = pkt.pos;
+
+               switch( avctx->codec_type ) {
+               case AVMEDIA_TYPE_VIDEO: {
+                       int vidx = ffvideo.size();
+                       while( --vidx>=0 && ffvideo[vidx]->fidx != i );
+                       if( vidx < 0 ) break;
+                       FFVideoStream *vid = ffvideo[vidx];
+                       int64_t tstmp = pkt.dts;
+                       if( tstmp == AV_NOPTS_VALUE ) tstmp = pkt.pts;
+                       if( tstmp != AV_NOPTS_VALUE && (pkt.flags & AV_PKT_FLAG_KEY) && pkt.pos > 0 ) {
+                               if( vid->nudge != AV_NOPTS_VALUE ) tstmp -= vid->nudge;
+                               double secs = to_secs(tstmp, st->time_base);
+                               int64_t frm = secs * vid->frame_rate + 0.5;
+                               if( frm < 0 ) frm = 0;
+                               index_state->put_video_mark(vidx, frm, pkt.pos);
+                       }
+#if 0
+                       while( pkt.size > 0 ) {
+                               av_frame_unref(frame);
+                               int got_frame = 0;
+                               int ret = vid->decode_frame(&pkt, frame, got_frame);
+                               if( ret <= 0 ) break;
+//                             if( got_frame ) {}
+                               pkt.data += ret;
+                               pkt.size -= ret;
+                       }
+#endif
+                       break; }
+               case AVMEDIA_TYPE_AUDIO: {
+                       int aidx = ffaudio.size();
+                       while( --aidx>=0 && ffaudio[aidx]->fidx != i );
+                       if( aidx < 0 ) break;
+                       FFAudioStream *aud = ffaudio[aidx];
+                       int64_t tstmp = pkt.pts;
+                       if( tstmp == AV_NOPTS_VALUE ) tstmp = pkt.dts;
+                       if( tstmp != AV_NOPTS_VALUE && (pkt.flags & AV_PKT_FLAG_KEY) && pkt.pos > 0 ) {
+                               if( aud->nudge != AV_NOPTS_VALUE ) tstmp -= aud->nudge;
+                               double secs = to_secs(tstmp, st->time_base);
+                               int64_t sample = secs * aud->sample_rate + 0.5;
+                               if( sample < 0 ) sample = 0;
+                               index_state->put_audio_mark(aidx, sample, pkt.pos);
+                       }
+                       while( pkt.size > 0 ) {
+                               int ch = aud->channel0,  nch = aud->channels;
+                               int64_t pos = index_state->pos(ch);
+                               if( pos != aud->curr_pos ) {
+if( abs(pos-aud->curr_pos) > 1 )
+printf("audio%d pad %ld %ld (%ld)\n", aud->idx, pos, aud->curr_pos, pos-aud->curr_pos);
+                                       index_state->pad_data(ch, nch, aud->curr_pos);
+                               }
+                               av_frame_unref(frame);
+                               int got_frame = 0;
+                               int ret = aud->decode_frame(&pkt, frame, got_frame);
+                               if( ret <= 0 ) break;
+                               if( got_frame ) {
+                                       float *samples;
+                                       int len = aud->get_samples(samples,
+                                                &frame->extended_data[0], frame->nb_samples);
+                                       for( int i=0; i<nch; ++i )
+                                               index_state->put_data(ch+i,nch,samples+i,len);
+                                       aud->curr_pos += len;
+                               }
+                               pkt.data += ret;
+                               pkt.size -= ret;
+                       }
+                       break; }
+               default: break;
+               }
+       }
+       av_frame_free(&frame);
+       return 0;
+}
+
+void FFStream::load_markers(IndexMarks &marks, double rate)
+{
+       index_markers = &marks;
+       int in = 0;
+       int64_t sz = marks.size();
+       int max_entries = fmt_ctx->max_index_size / sizeof(AVIndexEntry) - 1;
+       int nb_ent = st->nb_index_entries;
+// some formats already have an index
+       if( nb_ent > 0 ) {
+               AVIndexEntry *ep = &st->index_entries[nb_ent-1];
+               int64_t tstmp = ep->timestamp;
+               if( nudge != AV_NOPTS_VALUE ) tstmp -= nudge;
+               double secs = ffmpeg->to_secs(tstmp, st->time_base);
+               int64_t no = secs * rate;
+               while( in < sz && marks[in].no <= no ) ++in;
+       }
+       int64_t len = sz - in;
+       int64_t count = max_entries - nb_ent;
+       if( count > len ) count = len;
+       for( int i=0; i<count; ++i ) {
+               int k = in + i * len / count;
+               int64_t no = marks[k].no, pos = marks[k].pos;
+               double secs = (double)no / rate;
+               int64_t tstmp = secs * st->time_base.den / st->time_base.num;
+               if( nudge != AV_NOPTS_VALUE ) tstmp += nudge;
+               av_add_index_entry(st, pos, tstmp, 0, 0, AVINDEX_KEYFRAME);
+       }
+}
+
index 8400751bc5f63329f8c6271c2d509f88e7675b79..92fabfcdc5367a26b7ffec01c7050ea44212f69b 100644 (file)
@@ -17,6 +17,7 @@
 #include "ffmpeg.inc"
 #include "filebase.inc"
 #include "fileffmpeg.inc"
+#include "indexstate.inc"
 #include "mutex.h"
 #include "thread.h"
 #include "vframe.inc"
@@ -67,7 +68,7 @@ public:
 
 class FFStream {
 public:
-       FFStream(FFMPEG *ffmpeg, AVStream *st, int idx);
+       FFStream(FFMPEG *ffmpeg, AVStream *st, int fidx);
        ~FFStream();
        static void ff_lock(const char *cp=0);
        static void ff_unlock();
@@ -77,15 +78,20 @@ public:
        virtual int encode_activate();
        virtual int decode_activate();
        int read_packet();
+       int seek(int64_t no, double rate);
        int write_packet(FFPacket &pkt);
        int flush();
        int decode(AVFrame *frame);
+       void load_markers(IndexMarks &marks, double rate);
 
-       virtual int decode_frame(AVFrame *frame, int &got_frame) = 0;
-       virtual int encode_frame(FFPacket &pkt, AVFrame *frame, int &got_frame) = 0;
+       virtual int is_audio() = 0;
+       virtual int is_video() = 0;
+       virtual int decode_frame(AVPacket *pkt, AVFrame *frame, int &got_frame) = 0;
+       virtual int encode_frame(AVPacket *pkt, AVFrame *frame, int &got_frame) = 0;
        virtual int init_frame(AVFrame *frame) = 0;
        virtual int create_filter(const char *filter_spec,
                AVCodecContext *src_ctx, AVCodecContext *sink_ctx) = 0;
+       virtual void load_markers() = 0;
        int create_filter(const char *filter_spec);
        int load_filter(AVFrame *frame);
        int read_filter(AVFrame *frame);
@@ -123,11 +129,13 @@ public:
        int frm_count;
        List<FFrame> frms;
        Mutex *frm_lock;
+       IndexMarks *index_markers;
 
        int64_t nudge;
-       int idx;
+       int64_t seek_pos, curr_pos;
+       int fidx;
        int reading, writing;
-       int eof;
+       int seeked, eof;
 
        int st_eof() { return eof; }
        void st_eof(int v) { eof = v; }
@@ -135,16 +143,15 @@ public:
 
 class FFAudioStream : public FFStream {
        float *inp, *outp, *bfr, *lmt;
-       long sz;
+       int64_t hpos, sz;
        int nch;
 
        int read(float *fp, long len);
-       void realloc(long sz, int nch, long len);
-       void realloc(long sz, int nch);
-       void reserve(long sz, int nch);
+       void realloc(long nsz, int nch, long len);
+       void realloc(long nsz, int nch);
+       void reserve(long nsz, int nch);
        long used();
        long avail();
-       void reset();
        void iseek(int64_t ofs);
        float *get_outp(int len);
        int64_t put_inp(int len);
@@ -152,18 +159,23 @@ class FFAudioStream : public FFStream {
        int zero(long len);
        int write(const double *dp, long len, int ch);
 public:
-       FFAudioStream(FFMPEG *ffmpeg, AVStream *strm, int idx);
+       FFAudioStream(FFMPEG *ffmpeg, AVStream *strm, int idx, int fidx);
        virtual ~FFAudioStream();
+       int is_audio() { return 1; }
+       int is_video() { return 0; }
+       int get_samples(float *&samples, uint8_t **data, int len);
        int load_history(uint8_t **data, int len);
-       int decode_frame(AVFrame *frame, int &got_frame);
-       int encode_frame(FFPacket &pkt, AVFrame *frame, int &got_frame);
+       int decode_frame(AVPacket *pkt, AVFrame *frame, int &got_frame);
+       int encode_frame(AVPacket *pkt, AVFrame *frame, int &got_frame);
        int create_filter(const char *filter_spec,
                AVCodecContext *src_ctx, AVCodecContext *sink_ctx);
+       void load_markers();
 
        int encode_activate();
        int nb_samples();
        int64_t load_buffer(double ** const sp, int len);
        int in_history(int64_t pos);
+       void reset_history();
        int read(double *dp, long len, int ch);
 
        int init_frame(AVFrame *frame);
@@ -171,10 +183,10 @@ public:
        int audio_seek(int64_t pos);
        int encode(double **samples, int len);
 
+       int idx;
        int channel0, channels;
        int sample_rate;
        int mbsz, frame_sz;
-       int64_t seek_pos, curr_pos;
        int64_t length;
 
        SwrContext *resample_context;
@@ -184,27 +196,31 @@ public:
 
 class FFVideoStream : public FFStream {
 public:
-       FFVideoStream(FFMPEG *ffmpeg, AVStream *strm, int idx);
+       FFVideoStream(FFMPEG *ffmpeg, AVStream *strm, int idx, int fidx);
        virtual ~FFVideoStream();
-       int decode_frame(AVFrame *frame, int &got_frame);
-       int encode_frame(FFPacket &pkt, AVFrame *frame, int &got_frame);
+       int is_audio() { return 0; }
+       int is_video() { return 1; }
+       int decode_frame(AVPacket *pkt, AVFrame *frame, int &got_frame);
+       int encode_frame(AVPacket *pkt, AVFrame *frame, int &got_frame);
        int create_filter(const char *filter_spec,
                AVCodecContext *src_ctx, AVCodecContext *sink_ctx);
+       void load_markers();
 
        int init_frame(AVFrame *picture);
        int load(VFrame *vframe, int64_t pos);
        int video_seek(int64_t pos);
        int encode(VFrame *vframe);
 
+       int idx;
        double frame_rate;
        int width, height;
-       int64_t seek_pos, curr_pos;
        int64_t length;
        float aspect_ratio;
 
        struct SwsContext *convert_ctx;
        uint8_t *pkt_bfr;
        int pkt_bfr_sz;
+       int64_t start_pts;
 
        static PixelFormat color_model_to_pix_fmt(int color_model);
        static int pix_fmt_to_color_model(PixelFormat pix_fmt);
@@ -282,7 +298,7 @@ public:
                uint16_t st_idx, st_ch;
                ffidx() { st_idx = st_ch = 0; }
                ffidx(const ffidx &t) { st_idx = t.st_idx;  st_ch = t.st_ch; }
-               ffidx(uint16_t idx, uint16_t ch) { st_idx = idx; st_ch = ch; }
+               ffidx(uint16_t fidx, uint16_t ch) { st_idx = fidx; st_ch = ch; }
        };
 
        ArrayList<ffidx> astrm_index;
@@ -306,6 +322,7 @@ public:
 
        FFMPEG(FileBase *file_base=0);
        ~FFMPEG();
+       int scan(IndexState *index_state, int64_t *scan_position, int *canceled);
 
        int ff_audio_stream(int channel) { return astrm_index[channel].st_idx; }
        int ff_video_stream(int layer) { return vstrm_index[layer].st_idx; }
index 44cc26104108c76821e003aecba321a8fc5ccdd7..a072e9c0c25fef406dfaaec971bfa78cdad132d7 100644 (file)
@@ -44,7 +44,6 @@ extern "C"
 #include "file.h"
 #include "filempeg.h"
 #include "language.h"
-#include "mwindow.inc"
 #include "mainerror.h"
 
 
@@ -298,10 +297,7 @@ int FileAC3::write_samples(double **buffer, int64_t len)
                        int got_packet = 0;
                        ret = avcodec_encode_audio2(avctx, &avpkt, frame, &got_packet);
                        if( !ret ) {
-                               if(got_packet && avctx->coded_frame) {
-                                       avctx->coded_frame->pts = avpkt.pts;
-                                       avctx->coded_frame->key_frame = !!(avpkt.flags & AV_PKT_FLAG_KEY);
-                               }
+                               fprintf(stderr, "avcodec_encode_audio2 failed. \n%m\n");
                        }
                }
                av_packet_free_side_data(&avpkt);
index 90c1a6ef62071f3fb52bb5d96131f729949f2962..b195623e05e00cc3b866273230a37e8b2f3970d4 100644 (file)
@@ -9,13 +9,17 @@
 
 #include "asset.h"
 #include "bcwindowbase.h"
+#include "bcprogressbox.h"
 #include "bitspopup.h"
 #include "ffmpeg.h"
 #include "filebase.h"
 #include "file.h"
 #include "fileffmpeg.h"
 #include "filesystem.h"
+#include "format.inc"
+#include "indexfile.h"
 #include "mutex.h"
+#include "preferences.h"
 #include "videodevice.inc"
 
 FileFFMPEG::FileFFMPEG(Asset *asset, File *file)
@@ -220,6 +224,8 @@ int FileFFMPEG::open_file(int rd, int wr)
                                if( !asset->video_length ) asset->video_length = ff->ff_video_frames(0);
                                if( !asset->frame_rate ) asset->frame_rate = ff->ff_frame_rate(0);
                        }
+                       IndexState *index_state = asset->index_state;
+                       index_state->read_markers(file->preferences->index_directory, asset->path);
                }
        }
        else if( wr ) {
@@ -598,4 +604,87 @@ int FFMPEGConfigVideoToggle::handle_event()
        return 1;
 }
 
+FFMPEGScanProgress::FFMPEGScanProgress(const char *title, int64_t length, int64_t *position, int *canceled)
+ : Thread(1, 0, 0)
+{
+       strcpy(this->progress_title, title);
+       this->length = length;
+       this->position = position;
+       this->canceled = canceled;
+       done = 0;
+       progress = 0;
+       start();
+}
+
+FFMPEGScanProgress::~FFMPEGScanProgress()
+{
+       done = 1;
+       cancel();
+       join();
+}
+
+void FFMPEGScanProgress::run()
+{
+       BC_ProgressBox *progress = new BC_ProgressBox(-1, -1, progress_title, length);
+       progress->start();
+
+       struct timeval start_time, now, then;
+       gettimeofday(&start_time, 0);
+       then = start_time;
+
+       while( !done ) {
+               if( progress->update(*position, 1) ) {
+                       *canceled = done = 1;
+                       break;
+               }
+               gettimeofday(&now, 0);
+               if(now.tv_sec - then.tv_sec >= 1) {
+                       int64_t elapsed = now.tv_sec - start_time.tv_sec;
+                       int64_t byte_rate = *position / elapsed;
+                       int64_t eta = !byte_rate ? 0 : (length - *position) / byte_rate;
+                       char string[BCTEXTLEN];
+                       sprintf(string, "%s\nETA: " _LD "m" _LD "s",
+                               progress_title, eta / 60, eta % 60);
+                       progress->update_title(string, 1);
+                       then = now;
+               }
+               usleep(500000);
+       }
+
+       progress->stop_progress();
+       delete progress;
+}
+
+int FileFFMPEG::get_index(char *index_path)
+{
+       if( !ff ) return -1;
+       if( !file->preferences->ffmpeg_marker_indecies ) return 1;
+
+       IndexState *index_state = asset->index_state;
+       if( index_state->index_status != INDEX_NOTTESTED ) return 0;
+       index_state->index_status = INDEX_BUILDING;
+
+       for( int aidx=0; aidx<ff->ffaudio.size(); ++aidx ) {
+               FFAudioStream *aud = ff->ffaudio[aidx];
+               index_state->add_audio_stream(aud->channels, aud->length);
+       }
+
+       char progress_title[BCTEXTLEN];
+       sprintf(progress_title, _("Creating %s\n"), index_path);
+        FileSystem fs;
+       int64_t file_bytes = fs.get_size(ff->fmt_ctx->filename);
+       int64_t scan_position = 0;
+       int canceled = 0;
+       FFMPEGScanProgress scan_progress(progress_title, file_bytes, &scan_position, &canceled);
+
+       index_state->index_bytes = file_bytes;
+       index_state->init_scan(file->preferences->index_size);
+       if( ff->scan(index_state, &scan_position, &canceled) || canceled ) {
+               index_state->reset_index();
+               index_state->reset_markers();
+               return 1;
+       }
+       index_state->marker_status = MARKERS_READY;
+       return index_state->create_index(index_path, asset);
+}
 
index bde3d5d5f5f34541e8d6a0db80a0b329ee82dabd..ed95ee9460740e2b12c98f6d6999ab9b38ca6bcc 100644 (file)
@@ -3,11 +3,12 @@
 
 #include "asset.inc" 
 #include "bcwindowbase.inc"
+#include "bcprogressbox.inc"
 #include "bitspopup.inc" 
 #include "filebase.h"
 #include "fileffmpeg.inc"
-#include "mwindow.inc"
 #include "mutex.h"
+#include "thread.h"
 #include "vframe.inc"
 
 #include <stdio.h>
@@ -49,6 +50,7 @@ public:
        int get_audio_for_video(int vstream, int astream, int64_t &channel_mask);
        static void get_info(char *path,char *text,int len);
        int open_file(int rd,int wr);
+       int get_index(char *index_filename);
        int close_file(void);
        int set_video_position(int64_t pos);
        int set_audio_position(int64_t pos);
@@ -214,4 +216,17 @@ public:
        FFMPEGConfigVideo *popup;
 };
 
+class FFMPEGScanProgress : public Thread
+{
+public:
+       char progress_title[BCTEXTLEN];
+       BC_ProgressBox *progress;
+       int64_t length, *position;
+       int done, *canceled;
+
+       FFMPEGScanProgress(const char *title, int64_t length, int64_t *position, int *canceled);
+       ~FFMPEGScanProgress();
+       void run();
+};
+
 #endif
index dfd271818a19008edae83f06d9dc3de9aa3060ac..b8e9c497ff7344d58d71934f45cc9d21eef33be6 100644 (file)
@@ -1027,56 +1027,23 @@ int FileMPEG::get_index(char *index_path)
 
 
 // Convert the index tables from tracks to channels.
-       if(mpeg3_index_tracks(fd))
-       {
-// Calculate size of buffer needed for all channels
-               int buffer_size = 0;
-               for(int i = 0; i < mpeg3_index_tracks(fd); i++)
-               {
-                       buffer_size += mpeg3_index_size(fd, i) *
-                               mpeg3_index_channels(fd, i) *
-                               2;
-               }
-
+       if(mpeg3_index_tracks(fd)) {
                IndexState *index_state = asset->index_state;
-               index_state->index_buffer = new float[buffer_size];
-
-               int index_channels = 0;
-               for(int i = 0; i < mpeg3_index_tracks(fd); i++)
-                       index_channels += mpeg3_index_channels(fd, i);
-// Size of index buffer in floats
-               int current_offset = 0;
-// Current asset channel
-               int current_channel = 0;
-               index_state->channels = index_channels;
-               index_state->index_zoom = mpeg3_index_zoom(fd);
-               index_state->index_offsets = new int64_t[index_channels];
-               index_state->index_sizes = new int64_t[index_channels];
-               for(int i = 0; i < mpeg3_index_tracks(fd); i++)
-               {
-                       for(int j = 0; j < mpeg3_index_channels(fd, i); j++)
-                       {
-                               index_state->index_offsets[current_channel] = current_offset;
-                               index_state->index_sizes[current_channel] = mpeg3_index_size(fd, i) * 2;
-                               memcpy(index_state->index_buffer + current_offset,
-                                       mpeg3_index_data(fd, i, j),
-                                       mpeg3_index_size(fd, i) * sizeof(float) * 2);
-
-                               current_offset += mpeg3_index_size(fd, i) * 2;
-                               current_channel++;
+               int index_zoom = mpeg3_index_zoom(fd);
+               int ntracks = mpeg3_index_tracks(fd);
+               int64_t offset = 0;
+               for(int i = 0; i < ntracks; i++) {
+                       int nch = mpeg3_index_channels(fd, i);
+                       for(int j = 0; j < nch; j++) {
+                               float *bfr = (float *)mpeg3_index_data(fd, i, j);
+                               int64_t size = 2*mpeg3_index_size(fd, i);
+                               index_state->add_index_entry(bfr, offset, size);
+                               offset += size;
                        }
                }
-
                FileSystem fs;
-               index_state->index_bytes = fs.get_size(asset->path);
-
-               index_state->write_index(index_path, 
-                       buffer_size * sizeof(float),
-                       asset,
-                       asset->audio_length);
-               delete [] index_state->index_buffer;
-
-               return 0;
+               int64_t file_bytes = fs.get_size(asset->path);
+               return index_state->write_index(index_path, asset, index_zoom, file_bytes);
        }
 
        return 1;
index aa80ae8d8ba674e7f64cac109aa565b716a5e2c6..e5ce7b765d3f2625eb012dd5b4975c1b5aca4ce3 100644 (file)
@@ -36,6 +36,8 @@
 #define eprintf printf
 
 static const char left_delm = '<', right_delm = '>';
+const char *FileXML::xml_header = "<?xml version=\"1.0\"?>\n";
+const int FileXML::xml_header_size = strlen(xml_header);
 
 XMLBuffer::XMLBuffer(long buf_size, long max_size, int del)
 {
@@ -433,7 +435,12 @@ char* FileXML::get_data()
 }
 char* FileXML::string()
 {
-       return (char *)buffer->pos();
+       return (char *)buffer->str();
+}
+
+long FileXML::length()
+{
+       return buffer->otell();
 }
 
 char* FileXML::read_text()
@@ -510,33 +517,24 @@ int FileXML::read_text_until(const char *tag_end, char *out, int len)
 
 int FileXML::write_to_file(const char *filename)
 {
-       strcpy(this->filename, filename);
        FILE *out = fopen(filename, "wb");
        if( !out ) {
                eprintf("write_to_file %d \"%s\": %m\n", __LINE__, filename);
                return 1;
        }
-// Position may have been rewound after storing
-       const char *str = string();
-       long len = strlen(str);
-       fprintf(out, "<?xml version=\"1.0\"?>\n");
-       if( len && !fwrite(str, len, 1, out) ) {
-               eprintf("write_to_file %d \"%s\": %m\n", __LINE__, filename);
-               fclose(out);
-               return 1;
-       }
+       int ret = write_to_file(out, filename);
        fclose(out);
-       return 0;
+       return ret;
 }
 
-int FileXML::write_to_file(FILE *file)
+int FileXML::write_to_file(FILE *file, const char *filename)
 {
-       strcpy(filename, "");
-       fprintf(file, "<?xml version=\"1.0\"?>\n");
+       strcpy(this->filename, filename);
        const char *str = string();
        long len = strlen(str);
 // Position may have been rewound after storing
-       if( len && !fwrite(str, len, 1, file) ) {
+       if( !fwrite(xml_header, xml_header_size, 1, file) ||
+           ( len > 0 && !fwrite(str, len, 1, file) ) ) {
                eprintf("\"%s\": %m\n", filename);
                return 1;
        }
index d41d081c57d20da5db075e2f9afed4affcd81a8c..25d0ff66ef4baa54312d3b6e8ca283f24f1313c9 100644 (file)
@@ -50,6 +50,7 @@ public:
        void oseek(long pos) { inp = bfr + pos; }
        void iseek(long pos) { outp = bfr + pos; }
        unsigned char *pos(long ofs=0) { return bfr+ofs; }
+       unsigned char *str() { if( inp < lmt ) *inp = 0; return bfr; }
        int read(char *bp, int n);
        int write(const char *bp, int n);
 
@@ -136,7 +137,7 @@ public:
        int read_text_until(const char *tag_end, char *out, int len);
        int read_tag();
        int write_to_file(const char *filename);
-       int write_to_file(FILE *file);
+       int write_to_file(FILE *file, const char *filename="");
        int read_from_file(const char *filename, int ignore_error = 0);
        int read_from_string(char *string);
        char *(*decode)(char *bp, const char *sp, int n);
@@ -150,6 +151,7 @@ public:
        int rewind();
        char *get_data();
        char *string();
+       long length();
 
        XMLBuffer *buffer;
        int coded;
@@ -159,6 +161,8 @@ public:
        char *output;
        char left_delimiter, right_delimiter;
        char filename[MAX_TITLE];
+       static const char *xml_header;
+       static const int xml_header_size;
 };
 
 #endif
index 865877d8ad17700c4a1bfde50dc933d20d15dfda..fa86e313828488d74f5951cf195d4f3cba938dcc 100644 (file)
@@ -28,7 +28,6 @@
 Indexable::Indexable(int is_asset) : Garbage(is_asset ? "Asset" : "EDL")
 {
        index_state = new IndexState;
-       index_state->reset();
        this->is_asset = is_asset;
        strcpy(folder, MEDIA_FOLDER);
 }
@@ -36,7 +35,7 @@ Indexable::Indexable(int is_asset) : Garbage(is_asset ? "Asset" : "EDL")
 
 Indexable::~Indexable()
 {
-       delete index_state;
+       index_state->remove_user();
 }
 
 int Indexable::get_audio_channels()
@@ -54,13 +53,26 @@ int64_t Indexable::get_audio_samples()
        return 0;
 }
 
+void Indexable::update_path(char *new_path)
+{
+       strcpy(path, new_path);
+}
+
+void Indexable::update_index(Indexable *src)
+{
+       index_state->remove_user();
+       index_state = src->index_state;
+       index_state->add_user();
+}
+
 
 
 
 void Indexable::copy_indexable(Indexable *src)
 {
-       strcpy(path, src->path);
-       index_state->copy_from(src->index_state);
+       if( this == src ) return;
+       update_path(src->path);
+       update_index(src);
 }
 
 int Indexable::have_audio()
index 7e2631cb09cb37754723518095fc3f59391b0988..766af10f219b4e48b3298e88bf69fcb30e6cf2ae 100644 (file)
@@ -48,8 +48,9 @@ public:
        virtual int get_video_layers();
        virtual int64_t get_video_frames();
 
-
-       void copy_indexable(Indexable *src);
+        void copy_indexable(Indexable *src);
+       void update_path(char *new_path);
+       void update_index(Indexable *src);
 
        IndexState *index_state;
 
index 72dbb26ba6cc2005d322a242d991535ba52a6213..8a21db0ebfbf49ccca55563824f4a4e6ba1a0e67 100644 (file)
@@ -254,11 +254,9 @@ int IndexFile::open_file()
 // Get its last size without changing the real asset status.
                Indexable *test_indexable = new Indexable(0);
                if(indexable)
-               {
                        test_indexable->copy_indexable(indexable);
-               }
-
                read_info(test_indexable);
+               IndexState *index_state = test_indexable->index_state;
 
                FileSystem fs;
                if(fs.get_date(index_filename) < fs.get_date(test_indexable->path))
@@ -274,12 +272,12 @@ int IndexFile::open_file()
                        fd = 0;
                }
                else
-               if(fs.get_size(test_indexable->path) != test_indexable->index_state->index_bytes)
+               if(fs.get_size(test_indexable->path) != index_state->index_bytes)
                {
 // source file is a different size than index source file
                        if(debug) printf("IndexFile::open_file %d index_size=" _LD " source_size=" _LD "\n",
                                __LINE__,
-                               test_indexable->index_state->index_bytes,
+                               index_state->index_bytes,
                                fs.get_size(test_indexable->path));
                        result = 2;
                        fclose(fd);     
@@ -430,11 +428,8 @@ int IndexFile::interrupt_index()
 int IndexFile::create_index(MainProgressBar *progress)
 {
        int result = 0;
-
 SET_TRACE
 
-       IndexState *index_state = get_state();
-
        interrupt_flag = 0;
 
 // open the source file
@@ -453,16 +448,13 @@ SET_TRACE
 // Test for index in stream table of contents
        if(source && !source->get_index(index_filename))
        {
+               IndexState *index_state = get_state();
+               index_state->index_status = INDEX_READY;
                redraw_edits(1);
        }
        else
 // Build index from scratch
        {
-
-
-
-
-               index_state->index_zoom = get_required_scale();
 SET_TRACE
 
 // Indexes are now built for everything since it takes too long to draw
@@ -610,14 +602,10 @@ int IndexFile::redraw_edits(int force)
 
        if(difference > 250 || force)
        {
-               IndexState *index_state = get_state();
                redraw_timer->update();
-// Can't lock window here since the window is only redrawn when the pixel
-// count changes.
                mwindow->gui->lock_window("IndexFile::redraw_edits");
                mwindow->edl->set_index_file(indexable);
                mwindow->gui->draw_indexes(indexable);
-               index_state->old_index_end = index_state->index_end;
                mwindow->gui->unlock_window();
        }
        return 0;
@@ -640,7 +628,6 @@ int IndexFile::draw_index(
 
 SET_TRACE
        if(debug) printf("IndexFile::draw_index %d\n", __LINE__);
-// check against index_end when being built
        if(index_state->index_zoom == 0)
        {
                printf(_("IndexFile::draw_index: index has 0 zoom\n"));
@@ -675,30 +662,17 @@ SET_TRACE
        int64_t length = (int64_t)(w * 
                mwindow->edl->local_session->zoom_sample * 
                asset_over_session);
-
-       if(index_state->index_status == INDEX_BUILDING)
-       {
-               if(startsource + length > index_state->index_end)
-                       length = index_state->index_end - startsource;
-       }
-
-// length of index to read in samples * 2
        int64_t lengthindex = length / index_state->index_zoom * 2;
-// start of data in samples
        int64_t startindex = startsource / index_state->index_zoom * 2;  
+// length of index to read in floats
+// length of index available in floats
+       int64_t endindex = index_state->index_status == INDEX_BUILDING ?
+               index_state->get_channel_used(edit->channel) * 2 :
+               index_state->get_index_size(edit->channel);
 // Clamp length of index to read by available data
-       if(startindex + lengthindex > index_state->get_index_size(edit->channel))
-               lengthindex = index_state->get_index_size(edit->channel) - startindex;
-
-
-       if(debug) printf("IndexFile::draw_index %d length=" _LD ""
-                       " index_size=" _LD " lengthindex=" _LD "\n", 
-               __LINE__, length, index_state->get_index_size(edit->channel),
-               lengthindex);
-       if(lengthindex <= 0) return 0;
-
-
-
+       if(startindex + lengthindex >= endindex )
+               lengthindex = endindex - startindex;
+       if( lengthindex <= 0 ) return 0;
 
 // Actual length read from file in bytes
        int64_t length_read;   
@@ -707,7 +681,8 @@ SET_TRACE
        float *buffer = 0;
        int buffer_shared = 0;
        int center_pixel = mwindow->edl->local_session->zoom_track / 2;
-       if(mwindow->edl->session->show_titles) center_pixel += mwindow->theme->get_image("title_bg_data")->get_h();
+       if( mwindow->edl->session->show_titles )
+               center_pixel += mwindow->theme->get_image("title_bg_data")->get_h();
        //int miny = center_pixel - mwindow->edl->local_session->zoom_track / 2;
        //int maxy = center_pixel + mwindow->edl->local_session->zoom_track / 2;
        int x1 = 0, y1, y2;
@@ -716,18 +691,20 @@ SET_TRACE
                index_state->index_zoom * 
                asset_over_session;
 
-// get channel offset
-       startindex += index_state->get_index_offset(edit->channel);
 
 
        if(index_state->index_status == INDEX_BUILDING)
        {
 // index is in RAM, being built
-               buffer = &(index_state->index_buffer[startindex]);
+               buffer = index_state->get_channel_buffer(edit->channel);
+               if( !buffer ) return 0;
+               buffer += startindex;
                buffer_shared = 1;
        }
        else
        {
+// add channel offset
+               startindex += index_state->get_index_offset(edit->channel);
 // index is stored in a file
                buffer = new float[lengthindex + 1];
                buffer_shared = 0;
@@ -753,17 +730,18 @@ SET_TRACE
                }
        }
 
-
-
        canvas->set_color(mwindow->theme->audio_color);
 
-
        double current_frame = 0;
        float highsample = buffer[0];
        float lowsample = buffer[1];
        int prev_y1 = center_pixel;
        int prev_y2 = center_pixel;
        int first_frame = 1;
+       int zoom_y = mwindow->edl->local_session->zoom_y, zoom_y2 = zoom_y / 2;
+       int max_y = canvas->get_h();
+       int zmax_y = center_pixel + zoom_y2 - 1;
+       if( zmax_y < max_y ) max_y = zmax_y;
 SET_TRACE
 
        for(int bufferposition = 0; 
@@ -772,22 +750,12 @@ SET_TRACE
        {
                if(current_frame >= index_frames_per_pixel)
                {
-                       int next_y1 = (int)(center_pixel - highsample * mwindow->edl->local_session->zoom_y / 2);
-                       int next_y2 = (int)(center_pixel - lowsample * mwindow->edl->local_session->zoom_y / 2);
-                       if(next_y1 < 0) next_y1 = 0;
-                       if(next_y1 > canvas->get_h()) next_y1 = canvas->get_h();
-                       if(next_y2 < 0) next_y2 = 0;
-                       if(next_y2 > canvas->get_h()) next_y2 = canvas->get_h();
-                       if(next_y2 > center_pixel + mwindow->edl->local_session->zoom_y / 2 - 1) 
-                               next_y2 = center_pixel + mwindow->edl->local_session->zoom_y / 2 - 1;
-                       if(next_y1 > center_pixel + mwindow->edl->local_session->zoom_y / 2 - 1) 
-                               next_y1 = center_pixel + mwindow->edl->local_session->zoom_y / 2 - 1;
-
-                       int y1 = next_y1;
-                       int y2 = next_y2;
-
-
-
+                       int y1 = (int)(center_pixel - highsample * zoom_y2);
+                       int y2 = (int)(center_pixel - lowsample * zoom_y2);
+                       CLAMP(y1, 0, max_y);  int next_y1 = y1;
+                       CLAMP(y2, 0, max_y);  int next_y2 = y2;
+//printf("draw_line (%f,%f) = %d,%d,  %d,%d\n", lowsample, highsample, x1 + x, y1, x1 + x, y2);
 
 //SET_TRACE
 // A different algorithm has to be used if it's 1 sample per pixel and the
@@ -830,8 +798,8 @@ SET_TRACE
 // Get last column
        if(current_frame)
        {
-               y1 = (int)(center_pixel - highsample * mwindow->edl->local_session->zoom_y / 2);
-               y2 = (int)(center_pixel - lowsample * mwindow->edl->local_session->zoom_y / 2);
+               y1 = (int)(center_pixel - highsample * zoom_y2);
+               y2 = (int)(center_pixel - lowsample * zoom_y2);
                canvas->draw_line(x1 + x, y1, x1 + x, y2, pixmap);
        }
 
@@ -874,15 +842,9 @@ int IndexFile::read_info(Indexable *test_indexable)
 // Store format in actual asset.
 // If it's a nested EDL, we never want the format, just the index info.
        if(!test_indexable) test_indexable = indexable;
-
-
-       IndexState *index_state = 0;
-       if(test_indexable) 
-               index_state = test_indexable->index_state;
-       else
-               return 1;
+       if(!test_indexable) return 1;
        
-
+       IndexState * index_state = test_indexable->index_state;
        if(index_state->index_status == INDEX_NOTTESTED)
        {
 // read start of index data
index ee4144985f7fe7eaf4f9bc495580c2f3c55dbd86..55865f0802c42716ccc40a45bd9f31e1741919a2 100644 (file)
@@ -27,6 +27,7 @@
 #include "file.inc"
 #include "guicast.h"
 #include "indexable.inc"
+#include "indexfile.inc"
 #include "indexstate.inc"
 #include "indexthread.inc"
 #include "mainprogress.inc"
index 5ef34587503b4e90e47213f3fba262e92e5db21d..361739a956bfdf40f8f44b4d35602a0e8528261f 100644 (file)
 #define INDEXFILE_INC
 
 class IndexFile;
-class IndexState;
-
-// Index statuses
-#define INDEX_READY     0
-#define INDEX_NOTTESTED 1
-#define INDEX_BUILDING  2
-#define INDEX_TOOSMALL  3
 
 #endif
index 52eb0c8a802ae0e0888e4a8c9eeb60969b8b7026..6de431985f1a828955e30f8153a954c46652f541 100644 (file)
  */
 
 
+#include "arraylist.h"
 #include "asset.h"
+#include "clip.h"
 #include "filexml.h"
 #include "format.inc"
+#include "indexfile.h"
 #include "indexstate.h"
-#include "indexstate.inc"
 #include "language.h"
+#include "mainerror.h"
+#include "mutex.h"
 
 #include <stdio.h>
+#include <string.h>
 
+int IndexMarks::find(int64_t no)
+{
+       int l = -1, r = size();
+        while( (r - l) > 1 ) {
+               int i = (l+r) >> 1;
+               if( no > values[i].no ) l = i; else r = i;
+       }
+       return l;
+}
 
-IndexState::IndexState()
+IndexChannel::IndexChannel(IndexState *state, int64_t length)
 {
-       reset();
+       this->state = state;
+       this->length = length;
+       min = max = 0;
+       bfr = inp = 0;
+       size = 0;
+       zidx = 0;
 }
 
-IndexState::~IndexState()
+IndexChannel::~IndexChannel()
 {
-       delete [] index_offsets;
-       delete [] index_sizes;
-// Don't delete index buffer since it is shared with the index thread.
+       delete [] bfr;
 }
 
-void IndexState::reset()
+void IndexChannel::put_entry()
+{
+       inp->min = min;
+       inp->max = max;
+       ++inp;
+       max = -1; min = 1;
+       zidx = 0;
+}
+
+int64_t IndexChannel::pos()
+{
+       return used() * state->index_zoom + zidx;
+}
+
+void IndexChannel::pad_data(int64_t pos)
+{
+       CLAMP(pos, 0, length);
+       while( this->pos() < pos ) put_entry();
+       inp = bfr + pos / state->index_zoom;
+       zidx = pos % state->index_zoom;
+}
+
+void IndexState::reset_index()
 {
        index_status = INDEX_NOTTESTED;
-       index_start = old_index_end = index_end = 0;
-       index_offsets = 0;
-       index_sizes = 0;
+       index_start = 0;
        index_zoom = 0;
        index_bytes = 0;
-       index_buffer = 0;
-       channels = 0;
+       index_entries.remove_all_objects();
+       index_channels.remove_all_objects();
 }
 
-void IndexState::dump()
+void IndexState::reset_markers()
 {
-       printf("IndexState::dump this=%p\n", this);
-       printf("    channels=%d index_status=%d index_zoom=" _LD
-               " index_bytes=" _LD " index_offsets=%p\n",
-               channels, index_status, index_zoom,
-               index_bytes, index_offsets);
-       if(index_sizes)
-       {
-               printf("    index_sizes=");
-               for(int i = 0; i < channels; i++)
-                       printf(_LD " ", index_sizes[i]);
-               printf("\n");
-       }
+       marker_status = MARKERS_NOTTESTED;
+       video_markers.remove_all_objects();
+       audio_markers.remove_all_objects();
 }
 
-void IndexState::copy_from(IndexState *src)
+IndexState::IndexState()
+ : Garbage("IndexState")
 {
-       if(this == src) return;
-
-       delete [] index_offsets;
-       delete [] index_sizes;
-       index_offsets = 0;
-       index_sizes = 0;
-
-//printf("Asset::update_index 1 %d\n", index_status);
-       index_status = src->index_status;
-       index_zoom = src->index_zoom;    // zoom factor of index data
-       index_start = src->index_start;  // byte start of index data in the index file
-       index_bytes = src->index_bytes;  // Total bytes in source file for comparison before rebuilding the index
-       index_end = src->index_end;
-       old_index_end = src->old_index_end;      // values for index build
-       channels = src->channels;
-
-       if(src->index_offsets)
-       {
-               index_offsets = new int64_t[channels];
-               index_sizes = new int64_t[channels];
-
-               int i;
-               for(i = 0; i < channels; i++)
-               {
-// offsets of channels in index file in floats
-                       index_offsets[i] = src->index_offsets[i];  
-                       index_sizes[i] = src->index_sizes[i];
-               }
+       marker_lock = new Mutex("IndexState::marker_lock");
+       reset_index();
+       reset_markers();
+}
+
+IndexState::~IndexState()
+{
+       reset_index();
+       reset_markers();
+       delete marker_lock;
+}
+
+void IndexState::init_scan(int64_t index_length)
+{
+       index_zoom = 1;
+       int channels = index_channels.size();
+       if( !channels ) return;
+       int64_t max_samples = 0;
+       for( int ch=0; ch<channels; ++ch ) {
+               int64_t len = index_channels[ch]->length;
+               if( max_samples < len ) max_samples = len;
+       }
+       int64_t items = index_length / sizeof(IndexItem);
+       int64_t count = (items - channels) / channels + 1;
+       while( count*index_zoom < max_samples ) index_zoom *= 2;
+       for( int ch=0; ch<channels; ++ch ) {
+               IndexChannel *chn = index_channels[ch];
+               int64_t len = chn->length / index_zoom + 1;
+               chn->alloc(len);
+               chn->put_entry();
        }
+       reset_markers();
+}
 
-// pointer
-       index_buffer = src->index_buffer;
+void IndexState::dump()
+{
+       printf("IndexState::dump this=%p\n", this);
+       printf("    index_status=%d index_zoom=" _LD " index_bytes=" _LD "\n",
+               index_status, index_zoom, index_bytes);
+       printf("    index entries=%d\n", index_entries.size());
+       for( int i=0; i<index_entries.size(); ++i )
+               printf("  %d. ofs=" _LD ", sz=" _LD "\n", i,
+                       index_entries[i]->offset, index_entries[i]->size);
+       printf("\n");
 }
 
 void IndexState::write_xml(FileXML *file)
@@ -114,17 +155,13 @@ void IndexState::write_xml(FileXML *file)
        file->append_tag();
        file->append_newline();
 
-       if(index_offsets)
-       {
-               for(int i = 0; i < channels; i++)
-               {
-                       file->tag.set_title("OFFSET");
-                       file->tag.set_property("FLOAT", index_offsets[i]);
-                       file->append_tag();
-                       file->tag.set_title("SIZE");
-                       file->tag.set_property("FLOAT", index_sizes[i]);
-                       file->append_tag();
-               }
+       for( int i=0; i<index_entries.size(); ++i ) {
+               file->tag.set_title("OFFSET");
+               file->tag.set_property("FLOAT", index_entries[i]->offset);
+               file->append_tag();
+               file->tag.set_title("SIZE");
+               file->tag.set_property("FLOAT", index_entries[i]->size);
+               file->append_tag();
        }
 
        file->append_newline();
@@ -135,18 +172,8 @@ void IndexState::write_xml(FileXML *file)
 
 void IndexState::read_xml(FileXML *file, int channels)
 {
-       this->channels = channels;
-
-       delete [] index_offsets;
-       delete [] index_sizes;
-       index_offsets = new int64_t[channels];
-       index_sizes = new int64_t[channels];
-
-       for(int i = 0; i < channels; i++) 
-       {
-               index_offsets[i] = 0;
-               index_sizes[i] = 0;
-       }
+       index_entries.remove_all_objects();
+       for( int i=0; i<channels; ++i ) add_index_entry(0, 0, 0);
 
        int current_offset = 0;
        int current_size = 0;
@@ -155,102 +182,204 @@ void IndexState::read_xml(FileXML *file, int channels)
        index_zoom = file->tag.get_property("ZOOM", 1);
        index_bytes = file->tag.get_property("BYTES", (int64_t)0);
 
-       while(!result)
-       {
+       while(!result) {
                result = file->read_tag();
-               if(!result)
-               {
-                       if(file->tag.title_is("/INDEX"))
-                       {
+               if(!result) {
+                       if(file->tag.title_is("/INDEX")) {
                                result = 1;
                        }
-                       else
-                       if(file->tag.title_is("OFFSET"))
-                       {
-                               if(current_offset < channels)
-                               {
-                                       index_offsets[current_offset++] = file->tag.get_property("FLOAT", 0);
+                       else if(file->tag.title_is("OFFSET")) {
+                               if(current_offset < channels) {
+                                       int64_t offset = file->tag.get_property("FLOAT", (int64_t)0);
+                                       index_entries[current_offset++]->offset = offset;
 //printf("Asset::read_index %d %d\n", current_offset - 1, index_offsets[current_offset - 1]);
                                }
                        }
-                       else
-                       if(file->tag.title_is("SIZE"))
-                       {
-                               if(current_size < channels)
-                               {
-                                       index_sizes[current_size++] = file->tag.get_property("FLOAT", 0);
+                       else if(file->tag.title_is("SIZE")) {
+                               if(current_size < channels) {
+                                       int64_t size = file->tag.get_property("FLOAT", (int64_t)0);
+                                       index_entries[current_size++]->size = size;
                                }
                        }
                }
        }
 }
 
-int IndexState::write_index(const char *path, 
-       int data_bytes, 
-       Asset *asset,
-       int64_t length_source)
+int IndexState::write_index(const char *index_path, Asset *asset, int64_t zoom, int64_t file_bytes)
 {
-
-       FILE *file;
-       if(!(file = fopen(path, "wb")))
-       {
-// failed to create it
-               printf(_("IndexState::write_index Couldn't write index file %s to disk.\n"), 
-                       path);
+        FILE *fp = fopen(index_path, "wb");
+        if( !fp ) {
+               eprintf(_("IndexState::write_index Couldn't write index file %s to disk.\n"),
+                       index_path);
+               return 1;
        }
+       index_zoom = zoom;
+       index_bytes = file_bytes;
+       index_status = INDEX_READY;
+
+       FileXML xml;
+// write index_state as asset or directly.
+       if( asset )
+               asset->write(&xml, 1, "");
        else
-       {
-               FileXML xml;
-// Pad index start position
-               fwrite((char*)&(index_start), sizeof(int64_t), 1, file);
-
-               index_status = INDEX_READY;
-
-// Write asset encoding information in index file.
-// This also calls back into index_state to write it.
-               if(asset)
-               {
-                       asset->write(&xml, 
-                               1, 
-                               "");
-               }
-               else
-               {
-// Must write index_state directly.
-                       write_xml(&xml);
-               }
+               write_xml(&xml);
+       int64_t len = xml.length() + FileXML::xml_header_size;
+       index_start = sizeof(index_start) + len;
+       fwrite(&index_start, sizeof(index_start), 1, fp);
+       xml.write_to_file(fp);
+
+       int channels = index_entries.size();
+       int64_t max_size = 0;
+       for( int ch=0; ch<channels; ++ch ) {
+               IndexEntry *ent = index_entries[ch];
+               float *bfr = ent->bfr;
+               int64_t size = ent->size;
+               if( max_size < size ) max_size = size;
+               fwrite(bfr, sizeof(float), size, fp);
+       }
+
+       fclose(fp);
+       reset_index();
+       return 0;
+}
 
-               xml.write_to_file(file);
-               index_start = ftell(file);
-               fseek(file, 0, SEEK_SET);
-// Write index start
-               fwrite((char*)&(index_start), sizeof(int64_t), 1, file);
-               fseek(file, index_start, SEEK_SET);
-
-// Write index data
-               fwrite(index_buffer, 
-                       data_bytes, 
-                       1, 
-                       file);
-               fclose(file);
+int IndexState::write_markers(const char *index_path)
+{
+       int vid_size = video_markers.size();
+       int aud_size = audio_markers.size();
+       if( !vid_size && !aud_size ) return 0;
+
+       FILE *fp = 0;
+       char marker_path[BCTEXTLEN];
+       strcpy(marker_path, index_path);
+       char *basename = strrchr(marker_path,'/');
+       if( !basename ) basename = marker_path;
+       char *ext = strrchr(basename, '.');
+       if( ext ) {
+               strcpy(ext, ".mkr");
+               fp = fopen(marker_path, "wb");
        }
 
-// Force reread of header
-       index_status = INDEX_NOTTESTED;
-       index_end = length_source;
-       old_index_end = 0;
-       index_start = 0;
+       char version[] = MARKER_MAGIC_VERSION;
+        if( !fp || !fwrite(version, strlen(version), 1, fp) ) {
+               eprintf(_("IndexState::write_markers Couldn't write marker file %s to disk.\n"),
+                       marker_path);
+               return 1;
+       }
+
+       fwrite(&vid_size, sizeof(vid_size), 1, fp);
+       for( int vidx=0; vidx<vid_size; ++vidx ) {
+               IndexMarks &marks = *video_markers[vidx];
+               int count = marks.size();
+               fwrite(&count, sizeof(count), 1, fp);
+               fwrite(&marks[0], sizeof(marks[0]), count, fp);
+       }
+
+       fwrite(&aud_size, sizeof(aud_size), 1, fp);
+       for( int aidx=0; aidx<aud_size; ++aidx ) {
+               IndexMarks &marks = *audio_markers[aidx];
+               int count = marks.size();
+               fwrite(&count, sizeof(count), 1, fp);
+               fwrite(&marks[0], sizeof(marks[0]), marks.size(), fp);
+       }
+
+       fclose(fp);
        return 0;
 }
 
+int IndexState::read_markers(char *index_dir, char *file_path)
+{
+       int ret = 0;
+       marker_lock->lock("IndexState::read_markers");
+       if( marker_status == MARKERS_NOTTESTED ) {
+               char src_path[BCTEXTLEN], marker_path[BCTEXTLEN];
+               IndexFile::get_index_filename(src_path, index_dir, marker_path, file_path, ".mkr");
+               FILE *fp = fopen(marker_path, "rb");
+               int vsz = strlen(MARKER_MAGIC_VERSION);
+               char version[vsz];
+               if( fp && fread(version, vsz, 1, fp) ) {
+                       if( memcmp(version, MARKER_MAGIC_VERSION, vsz) ) {
+                               eprintf(_("IndexState::read_markers marker file version mismatched\n: %s\n"),
+                                       marker_path);
+                               return 1;
+                       }
+                       ret = read_marks(fp);
+                       if( !ret ) marker_status = MARKERS_READY;
+                       fclose(fp);
+               }
+       }
+       marker_lock->unlock();
+       return ret;
+}
+
+int IndexState::read_marks(FILE *fp)
+{
+       reset_markers();
+       int vid_size = 0;
+       if( !fread(&vid_size, sizeof(vid_size), 1, fp) ) return 1;
+       add_video_markers(vid_size);
+       for( int vidx=0; vidx<vid_size; ++vidx ) {
+               int count = 0;
+               if( !fread(&count, sizeof(count), 1, fp) ) return 1;
+               IndexMarks &marks = *video_markers[vidx];
+               marks.allocate(count);
+               int len = fread(&marks[0], sizeof(marks[0]), count, fp);
+               if( len != count ) return 1;
+               marks.total = count;
+       }
+       int aud_size = 0;
+       if( !fread(&aud_size, sizeof(aud_size), 1, fp) ) return 1;
+       add_audio_markers(aud_size);
+       for( int aidx=0; aidx<aud_size; ++aidx ) {
+               int count = 0;
+               if( !fread(&count, sizeof(count), 1, fp) ) return 1;
+               IndexMarks &marks = *audio_markers[aidx];
+               marks.allocate(count);
+               int len = fread(&marks[0], sizeof(marks[0]), count, fp);
+               if( len != count ) return 1;
+               marks.total = count;
+       }
+       return 0;
+}
+
+int IndexState::create_index(const char *index_path, Asset *asset)
+{
+       index_entries.remove_all_objects();
+       int channels = index_channels.size();
+       int64_t offset = 0;
+       for( int ch=0; ch<channels; ++ch ) {
+               IndexChannel *chn = index_channels[ch];
+               float *bfr = (float *)chn->bfr;
+               int64_t size = 2 * chn->used();
+               add_index_entry(bfr, offset, size);
+               offset += size;
+       }
+
+       write_markers(index_path);
+       return write_index(index_path, asset, index_zoom, index_bytes);
+}
+
 int64_t IndexState::get_index_offset(int channel)
 {
-       return channel < channels && index_offsets ? index_offsets[channel] : 0;
+       return channel >= index_entries.size() ? 0 :
+               index_entries[channel]->offset;
 }
 
 int64_t IndexState::get_index_size(int channel)
 {
-       return channel < channels && index_sizes ? index_sizes[channel] : 0;
+       return channel >= index_entries.size() ? 0 :
+               index_entries[channel]->size;
 }
 
+float *IndexState::get_channel_buffer(int channel)
+{
+       return channel >= index_channels.size() ? 0 :
+               (float *)index_channels[channel]->bfr;
+}
+
+int64_t IndexState::get_channel_used(int channel)
+{
+       return channel >= index_channels.size() ? 0 :
+               index_channels[channel]->used();
+}
 
index fd095875f34b302d3447230b4fc5803228ea5045..3280579de7a6199bf47b903810360f1bc1e11ffa 100644 (file)
 #ifndef INDEXSTATE_H
 #define INDEXSTATE_H
 
+#include "arraylist.h"
 #include "asset.inc"
 #include "filexml.inc"
+#include "garbage.h"
+#include "indexstate.inc"
+#include "mutex.inc"
 
+#include <stdio.h>
 #include <stdint.h>
 
+class IndexItem {
+public:
+       float max, min;
+};
+
+class IndexMark {
+public:
+       int64_t no, pos;
+       IndexMark() {}
+       IndexMark(int64_t n, int64_t p) { no = n;  pos = p; }
+
+       bool operator==(IndexMark &v) { return v.no == no; }
+       bool operator >(IndexMark &v) { return v.no > no; }
+};
+
+class IndexChannel : public IndexItem {
+public:
+       IndexChannel(IndexState *state, int64_t length);
+       ~IndexChannel();
+
+       IndexState *state;
+       IndexItem *bfr, *inp;
+       int64_t length, size;
+       int zidx;
+
+       void alloc(int64_t sz) { bfr = inp = new IndexItem[(size=sz)+1]; }
+       int64_t used() { return inp - bfr; }
+       int64_t avail() { return size - used(); }
+       int64_t pos();
+       void put_sample(float v, int zoom) {
+               if( v > max ) max = v;
+               if( v < min ) min = v;
+               if( ++zidx >= zoom )
+                       put_entry();
+       }
+       void put_entry();
+       void pad_data(int64_t pos);
+};
+
+class IndexChannels : public ArrayList<IndexChannel*> {
+public:
+       IndexChannels() {}
+       ~IndexChannels() { remove_all_objects(); }
+};
+
+
+class IndexEntry {
+public:
+       float *bfr;
+// offsets / sizes of channels in index buffer in floats
+       int64_t offset, size;
+       IndexEntry(float *bp, int64_t ofs, int64_t sz) {
+               bfr = bp;  offset = ofs;  size = sz;
+       }
+};
+
+class IndexEntries : public ArrayList<IndexEntry*> {
+public:
+       IndexEntries() {}
+       ~IndexEntries() { remove_all_objects(); }
+};
+
+class IndexMarks : public ArrayList<IndexMark> {
+public:
+       IndexMarks() {}
+       ~IndexMarks() {}
+       void add_mark(int64_t no, int64_t pos) { append(IndexMark(no, pos)); }
+       int find(int64_t no);
+};
+
+class IndexMarkers : public ArrayList<IndexMarks *> {
+public:
+       IndexMarkers() {}
+       ~IndexMarkers() { remove_all_objects(); }
+};
+
 // Assets & nested EDLs store this information to have their indexes built
-class IndexState
+class IndexState : public Garbage
 {
 public:
        IndexState();
        ~IndexState();
 
-       void reset();
-       void copy_from(IndexState *src);
+       void reset_index();
+       void reset_markers();
+       void init_scan(int64_t index_length);
+
 // Supply asset to include encoding information in index file.
        void write_xml(FileXML *file);
        void read_xml(FileXML *file, int channels);
-       int write_index(const char *path, 
-               int data_bytes, 
-               Asset *asset,
-               int64_t length_source);
+       int write_index(const char *index_path, Asset *asset, int64_t zoom, int64_t file_bytes);
+       int create_index(const char *index_path, Asset *asset);
+       int read_markers(char *index_dir, char *file_path);
+       int read_marks(FILE *fp);
+       int write_markers(const char *index_path);
        int64_t get_index_offset(int channel);
        int64_t get_index_size(int channel);
+       float *get_channel_buffer(int channel);
+       int64_t get_channel_used(int channel);
        void dump();
 
 // index info
-       int index_status;     // Macro from assets.inc
-       int64_t index_zoom;      // zoom factor of index data
-       int64_t index_start;     // byte start of index data in the index file
+       int index_status;       // Macro from assets.inc
+       int marker_status;
+       int64_t index_zoom;     // zoom factor of index data
+       int64_t index_start;    // byte start of index data in the index file
 // Total bytes in the source file when the index was buillt
        int64_t index_bytes;
-       int64_t index_end, old_index_end;    // values for index build
-// offsets of channels in index buffer in floats
-       int64_t *index_offsets;
-// Sizes of channels in index buffer in floats.  This allows
-// variable channel size.
-       int64_t *index_sizes;
-// [ index channel      ][ index channel      ]
-// [high][low][high][low][high][low][high][low]
-       float *index_buffer;  
-// Number of channels our buffers were allocated for
-       int channels;
-};
+        IndexChannels index_channels;
+       IndexEntries index_entries;
+       Mutex *marker_lock;
+       IndexMarkers video_markers;
+       IndexMarkers audio_markers;
 
+       void add_audio_channel(int64_t length) {
+               index_channels.append(new IndexChannel(this, length));
+       }
+       void add_audio_stream(int nch, int64_t length) {
+               for( int ch=0; ch<nch; ++ch ) add_audio_channel(length);
+       }
+       void add_video_markers(int n) {
+               while( --n >= 0 ) video_markers.append(new IndexMarks());
+       }
+       void add_audio_markers(int n) {
+               while( --n >= 0 ) audio_markers.append(new IndexMarks());
+       }
+       void add_index_entry(float *bfr, int64_t offset, int64_t size) {
+               index_entries.append(new IndexEntry(bfr, offset, size));
+       }
 
+       void put_data(int ch, int nch, float *data, int64_t len) {
+               IndexChannel *chn = index_channels[ch];
+               int64_t avl = chn->avail() * index_zoom - chn->zidx;
+               if( len > avl ) len = avl;
+               for( int64_t i=len; --i>=0; data+=nch )
+                       chn->put_sample(*data, index_zoom);
+       }
+       void put_data(int ch, double *data, int64_t len) {
+               IndexChannel *chn = index_channels[ch];
+               int64_t avl = chn->avail() * index_zoom - chn->zidx;
+               if( len > avl ) len = avl;
+               for( int64_t i=len; --i>=0; )
+                       chn->put_sample(*data++, index_zoom);
+       }
+       int64_t pos(int ch) { return index_channels[ch]->pos(); }
+       void pad_data(int ch, int nch, int64_t pos) {
+               while( --nch >= 0 ) index_channels[ch++]->pad_data(pos);
+       }
 
+       void put_video_mark(int vidx, int64_t frm, int64_t pos) {
+               if( vidx >= video_markers.size() ) return;
+               IndexMarks &marks = *video_markers[vidx];
+               if( marks.size()>0 && marks.last().no >= frm ) return;
+               marks.add_mark(frm, pos);
+       }
+       void put_audio_mark(int aidx, int64_t smpl, int64_t pos) {
+               if( aidx >= audio_markers.size() ) return;
+               IndexMarks &marks = *audio_markers[aidx];
+               if( marks.size()>0 && marks.last().no >= smpl ) return;
+               marks.add_mark(smpl, pos);
+       }
+};
 
 #endif
 
index adcffda5e2b723531a18c73d9d513f2c1cf65f1e..5bbb56d50d158d184ca82da77b50eeabd80f016d 100644 (file)
@@ -1,7 +1,17 @@
 #ifndef INDEXSTATE_INC
 #define INDEXSTATE_INC
 
+// magic number "mkr"  version = "1"
+#define MARKER_MAGIC_VERSION "mkr1"
 
+class IndexItem;
+class IndexMark;
+class IndexChannel;
+class IndexChannels;
+class IndexEntry;
+class IndexEntries;
+class IndexMarks;
+class IndexMarkers;
 class IndexState;
 
 // Index statuses
@@ -10,7 +20,7 @@ class IndexState;
 #define INDEX_BUILDING  2
 #define INDEX_TOOSMALL  3
 
+#define MARKERS_NOTTESTED 0
+#define MARKERS_READY   1
 
 #endif
-
-
index c990e5fbc7164c37a85b40a3a49839ad2b8a1a3d..efe938e3c1fec333d0e015816ef213b9696ac68a 100644 (file)
@@ -54,24 +54,6 @@ IndexThread::IndexThread(MWindow *mwindow,
        this->mwindow = mwindow;
        this->index_filename = index_filename;
        this->index_file = index_file;
-       IndexState *index_state = index_file->get_state();
-
-// initialize output data
-// size of output file in floats
-       int64_t index_size = mwindow->preferences->index_size / 
-               sizeof(float) + 1;
-
-       delete [] index_state->index_buffer;
-       delete [] index_state->index_offsets;
-       delete [] index_state->index_sizes;
-
-       index_state->channels = index_file->source_channels;
-// buffer used for drawing during the build.  This is not deleted in the index_state
-       index_state->index_buffer = new float[index_size];  
-// This is deleted in the index_state's destructor
-       index_state->index_offsets = new int64_t[index_state->channels];
-       index_state->index_sizes = new int64_t[index_state->channels];
-       bzero(index_state->index_buffer, index_size * sizeof(float));
 
 // initialization is completed in run
        for(int i = 0; i < TOTAL_INDEX_BUFFERS; i++)
@@ -84,7 +66,6 @@ IndexThread::IndexThread(MWindow *mwindow,
                output_lock[i] = new Condition(0, "IndexThread::output_lock");
                input_lock[i] = new Condition(1, "IndexThread::input_lock");
 
-
                for(int j = 0; j < index_file->source_channels; j++)
                {
                        buffer_in[i][j] = new Samples(buffer_size);
@@ -99,8 +80,6 @@ IndexThread::IndexThread(MWindow *mwindow,
 
 IndexThread::~IndexThread()
 {
-       IndexState *index_state = index_file->get_state();
-
        for(int i = 0; i < TOTAL_INDEX_BUFFERS; i++)
        {
                for(int j = 0; j < index_file->source_channels; j++)
@@ -111,9 +90,6 @@ IndexThread::~IndexThread()
                delete output_lock[i];
                delete input_lock[i];
        }
-       
-       delete [] index_state->index_buffer;
-       index_state->index_buffer = 0;
 }
 
 int IndexThread::start_build()
@@ -134,113 +110,26 @@ int IndexThread::stop_build()
 void IndexThread::run()
 {
        int done = 0;
-
-// current high samples in index
-       int64_t *highpoint;            
-// current low samples in the index
-       int64_t *lowpoint;             
-// position in current indexframe
-       int64_t *frame_position;
-       int first_point = 1;
        IndexState *index_state = index_file->get_state();
-
-       highpoint = new int64_t[index_file->source_channels];
-       lowpoint = new int64_t[index_file->source_channels];
-       frame_position = new int64_t[index_file->source_channels];
-
-// predict first highpoint for each channel plus padding and initialize it
-       for(int64_t channel = 0; channel < index_file->source_channels; channel++)
-       {
-               highpoint[channel] = 
-                       index_state->index_offsets[channel] = 
-                       (length_source / index_state->index_zoom * 2 + 1) * channel;
-               lowpoint[channel] = highpoint[channel] + 1;
-
-               index_state->index_sizes[channel] = 0;
-               frame_position[channel] = 0;
-       }
-
-       //int64_t index_start = 0;    // end of index during last edit update
-       index_state->index_end = 0;      // samples in source completed
-       index_state->old_index_end = 0;
+       int index_channels = index_file->source_channels;
+       index_state->add_audio_stream(index_channels, index_file->source_length);
+       index_state->init_scan(mwindow->preferences->index_size);
        index_state->index_status = INDEX_BUILDING;
-       int64_t zoomx = index_state->index_zoom;
-       float *index_buffer = index_state->index_buffer;    // output of index build
-       int64_t *index_sizes = index_state->index_sizes;
-       int64_t *index_offsets = index_state->index_offsets;
-//printf("IndexThread::run %d\n", __LINE__);
-//index_state->dump();
-//printf("IndexThread::run %d\n", __LINE__);
 
-       while(!interrupt_flag && !done)
-       {
+       while(!interrupt_flag && !done) {
                output_lock[current_buffer]->lock("IndexThread::run");
 
                if(last_buffer[current_buffer]) done = 1;
-               if(!interrupt_flag && !done)
-               {
+               if(!interrupt_flag && !done) {
 // process buffer
-                       int64_t fragment_size = input_len[current_buffer];
-
-// printf("IndexThread::run %d index_state->channels=%d index_file->source_channels=%d index_state->index_buffer=%p buffer_in=%p\n", 
-// __LINE__,
-// index_state->channels,
-// index_file->source_channels,
-// index_state->index_buffer,
-// buffer_in);
-                       for(int channel = 0; channel < index_file->source_channels; channel++)
-                       {
-SET_TRACE
-                               int64_t *highpoint_channel = &highpoint[channel];
-                               int64_t *lowpoint_channel = &lowpoint[channel];
-                               int64_t *frame_position_channel = &frame_position[channel];
-                               double *buffer_source = buffer_in[current_buffer][channel]->get_data();
-
-SET_TRACE
-                               for(int64_t i = 0; i < fragment_size; i++)
-                               {
-                                       if(*frame_position_channel == zoomx)
-                                       {
-                                               *highpoint_channel += 2;
-                                               *lowpoint_channel += 2;
-                                               *frame_position_channel = 0;
-// store and reset output values
-                                               index_buffer[*highpoint_channel] = 
-                                                       index_buffer[*lowpoint_channel] = 
-                                                       buffer_source[i];
-                                               index_sizes[channel] = 
-                                                       *lowpoint_channel - 
-                                                       index_offsets[channel] + 
-                                                       1;
-                                       }
-                                       else
-                                       {
-// get high and low points
-                                               if(first_point)
-                                               {
-                                                       index_buffer[*highpoint_channel] = 
-                                                               index_buffer[*lowpoint_channel] = buffer_source[i];
-                                                       first_point = 0;
-                                               }
-                                               else
-                                               {
-                                                       if(buffer_source[i] > index_buffer[*highpoint_channel]) 
-                                                               index_buffer[*highpoint_channel] = buffer_source[i];
-                                                       else 
-                                                       if(buffer_source[i] < index_buffer[*lowpoint_channel]) 
-                                                               index_buffer[*lowpoint_channel] = buffer_source[i];
-                                               }
-                                       }
-                                       (*frame_position_channel)++;
-                               } // end index one buffer
-SET_TRACE
+                       int64_t len = input_len[current_buffer];
+                       for( int ch=0; ch<index_channels; ++ch ) {
+                               double *samples = buffer_in[current_buffer][ch]->get_data();
+                               index_state->put_data(ch,samples,len);
                        }
 
-                       index_state->index_end += fragment_size;
-
 // draw simultaneously with build
                        index_file->redraw_edits(0);
-                       //index_start = index_state->index_end;
                }
 
                input_lock[current_buffer]->unlock();
@@ -251,15 +140,8 @@ SET_TRACE
        index_file->redraw_edits(1);
 
 // write the index file to disk
-       index_state->write_index(index_filename, 
-               (lowpoint[index_file->source_channels - 1] + 1) * sizeof(float),
-               index_file->indexable->is_asset ? (Asset*)index_file->indexable : 0,
-               index_file->source_length);
-
-
-       delete [] highpoint;
-       delete [] lowpoint;
-       delete [] frame_position;
+       Asset *asset = index_file->indexable->is_asset ? (Asset*)index_file->indexable : 0;
+       index_state->create_index(index_filename, asset);
 }
 
 
index d2836607b06d1d74ce58765268ae3e8c55dda8e6..fff91679888410a53ea1e2c548498bdb7b8d5f85 100644 (file)
@@ -71,7 +71,7 @@ void MButtons::create_objects()
        edit_panel->create_objects();
        
        x += edit_panel->get_w();
-       ffmpeg_toggle = new MainFFMpegToggle(mwindow, this, get_w()-30, 0);
+       ffmpeg_toggle = new MainFFMpegToggle(mwindow, this, get_w(), 0);
        add_subwindow(ffmpeg_toggle);
        flash(0);
 }
@@ -83,6 +83,7 @@ int MButtons::resize_event()
                mwindow->theme->mbuttons_w, 
                mwindow->theme->mbuttons_h);
        draw_top_background(get_parent(), 0, 0, get_w(), get_h());
+       ffmpeg_toggle->reposition_window(get_w()-30, 0);
        flash(0);
        return 0;
 }
index 35783daaae058833f8c440fde288ff6be9b40ee2..2c057c098197d1dd0feaf85b1cfd25ac0f51533a 100644 (file)
@@ -15,7 +15,7 @@
 
 
 
-void write_pbm(uint8_t *tp, int w, int h, const char *fmt, ...)
+void write_pgm(uint8_t *tp, int w, int h, const char *fmt, ...)
 {
   va_list ap;    va_start(ap, fmt);
   char fn[256];  vsnprintf(fn, sizeof(fn), fmt, ap);
@@ -28,7 +28,7 @@ void write_pbm(uint8_t *tp, int w, int h, const char *fmt, ...)
   }
 }
 
-void write_pgm(uint8_t *tp, int w, int h, const char *fmt, ...)
+void write_ppm(uint8_t *tp, int w, int h, const char *fmt, ...)
 {
   va_list ap;    va_start(ap, fmt);
   char fn[256];  vsnprintf(fn, sizeof(fn), fmt, ap);
index a53bd4c8c898c1bf18e8c9b17d67f5edd239e540..d9bbe2ac6ba1150c10b2f81088b32a89cf0f579c 100644 (file)
@@ -645,6 +645,8 @@ void MWindow::clean_indexes()
 //printf("MWindow::clean_indexes 2 %s\n", string2);
                                sprintf(ptr, ".toc");
                                remove(string2);
+                               sprintf(ptr, ".mkr");
+                               remove(string2);
                        }
                }
 
@@ -2605,6 +2607,7 @@ void MWindow::remove_indexfile(Indexable *indexable)
 // Erase file
        IndexFile::delete_index(preferences, asset, ".toc");
        IndexFile::delete_index(preferences, asset, ".idx");
+       IndexFile::delete_index(preferences, asset, ".mkr");
 }
 
 void MWindow::rebuild_indices()
index 86a41fcc8459ca611ac30b9d7a8facc496dd1306..b0c0f53f2144a0cd86864715c3f8b58398f5c679 100644 (file)
@@ -389,7 +389,6 @@ int MWindowGUI::resize_event(int w, int h)
        mwindow->session->mwindow_h = h;
        mwindow->theme->get_mwindow_sizes(this, w, h);
        mwindow->theme->draw_mwindow_bg(this);
-//     mainmenu->reposition_window(0, 0, w, mainmenu->get_h());
        mbuttons->resize_event();
        statusbar->resize_event();
        
@@ -469,6 +468,9 @@ int MWindowGUI::resize_event(int w, int h)
        zoombar->resize_event();
        pane_button->reposition_window(w - mwindow->theme->get_image_set("pane")[0]->get_w(), 
                mwindow->theme->mzoom_y + 1 - mwindow->theme->get_image_set("pane")[0]->get_h());
+       int x = get_w() - MainShBtns::calculate_w(0);
+       mainmenu->resize_event(x, mainmenu->get_h());
+       mainshbtns->reposition_window(x, 0);
 //     get_scrollbars(0);
 //     canvas->resize_event();
 //printf("MWindowGUI::resize_event %d\n", __LINE__);
index 3d1731c99d5053e0692823f376d0ea270731f211..4c7c64a05821197ddb8bf523aa1d799f6c1076b1 100644 (file)
@@ -84,7 +84,7 @@ void NestedEDLs::update_index(EDL *nested_edl)
 // __LINE__, 
 // current->index_state,
 // nested_edl->index_state->index_status);
-                       current->index_state->copy_from(nested_edl->index_state);
+                       current->update_index(nested_edl);
                }
        }
 }
index edc2f69e502ca71f3db23fd021eb0a95abda580b..3f77dce521347c450c343b43760cdde66300f7f3 100644 (file)
@@ -112,6 +112,9 @@ void PerformancePrefs::create_objects()
 
        ffmpeg_early_probe = new PrefsFFMPEGEarlyProbe(this, x, y);
        add_subwindow(ffmpeg_early_probe);
+       x1 = x + ffmpeg_early_probe->get_w() + 24;
+       ffmpeg_marker_indecies = new PrefsFFMPEGMarkerIndecies(this, x1, y);
+       add_subwindow(ffmpeg_marker_indecies);
        y += 30;
 
 
@@ -581,6 +584,7 @@ PrefsFFMPEGEarlyProbe::PrefsFFMPEGEarlyProbe(PerformancePrefs *perf_prefs, int x
 PrefsFFMPEGEarlyProbe::~PrefsFFMPEGEarlyProbe()
 {
 }
+
 int PrefsFFMPEGEarlyProbe::handle_event()
 {
        perf_prefs->pwindow->thread->preferences->ffmpeg_early_probe = get_value();
@@ -588,6 +592,24 @@ int PrefsFFMPEGEarlyProbe::handle_event()
 }
 
 
+PrefsFFMPEGMarkerIndecies::PrefsFFMPEGMarkerIndecies(PerformancePrefs *perf_prefs, int x, int y)
+ : BC_CheckBox(x, y, 
+       perf_prefs->pwindow->thread->preferences->ffmpeg_marker_indecies,
+       _("build ffmpeg marker indecies"))
+{
+       this->perf_prefs = perf_prefs;
+}
+PrefsFFMPEGMarkerIndecies::~PrefsFFMPEGMarkerIndecies()
+{
+}
+
+int PrefsFFMPEGMarkerIndecies::handle_event()
+{
+       perf_prefs->pwindow->thread->preferences->ffmpeg_marker_indecies = get_value();
+       return 1;
+}
+
+
 
 
 
index 0841ab82a17fe19e7f66667f94bb3e13694f79ae..7ac789cf4b2a6898fb05a62b5b230d41e97d5d14 100644 (file)
@@ -62,6 +62,7 @@ public:
        BC_Title *master_rate;
        PrefsFileForking *file_forking;
        PrefsFFMPEGEarlyProbe *ffmpeg_early_probe;
+       PrefsFFMPEGMarkerIndecies *ffmpeg_marker_indecies;
 };
 
 
@@ -167,6 +168,17 @@ public:
        PerformancePrefs *perf_prefs;
 };
 
+class PrefsFFMPEGMarkerIndecies : public BC_CheckBox
+{
+public:
+       PrefsFFMPEGMarkerIndecies(PerformancePrefs *perf_prefs, int x, int y);
+       ~PrefsFFMPEGMarkerIndecies();
+       
+       int handle_event();
+
+       PerformancePrefs *perf_prefs;
+};
+
 
 
 
index 806cfea87df027f6fc4b6da17006d09a939dab79..954b546c8a6ae5af0e8553adb91ab87063b1c65e 100644 (file)
@@ -31,6 +31,7 @@ class PrefsForceUniprocessor;
 class PrefsTrapSigSEGV;
 class PrefsTrapSigINTR;
 class PrefsFFMPEGEarlyProbe;
+class PrefsFFMPEGMarkerIndecies;
 class PrefsFileForking;
 class PrefsRenderFarm;
 class PrefsRenderFarmConsolidate;
index 0a8d33748ab8607d05a0726ee1516adb52cffe85..204acf32eb86276e97f9728df051358665ddd993 100644 (file)
@@ -70,12 +70,12 @@ Preferences::Preferences()
        sprintf(index_directory, BCASTDIR);
        if(strlen(index_directory))
                fs.complete_path(index_directory);
-       cache_size = 0xa00000;
-       index_size = 0x300000;
+       cache_size = 0x1000000;
+       index_size = 0x400000;
        index_count = 100;
        use_thumbnails = 1;
-       trap_sigsegv = 0;
-       trap_sigintr = 0;
+       trap_sigsegv = 1;
+       trap_sigintr = 1;
        theme[0] = 0;
        use_renderfarm = 0;
        force_uniprocessor = 0;
@@ -87,8 +87,9 @@ Preferences::Preferences()
        renderfarm_job_count = 20;
        processors = calculate_processors(0);
        real_processors = calculate_processors(1);
-       file_forking = 1;
+       file_forking = 0;
        ffmpeg_early_probe = 0;
+       ffmpeg_marker_indecies = 1;
        warn_indecies = 1;
 
 // Default brender asset
@@ -124,6 +125,8 @@ Preferences::Preferences()
 Preferences::~Preferences()
 {
        brender_asset->Garbage::remove_user();
+       shbtn_prefs.remove_all_objects();
+       renderfarm_nodes.remove_all_objects();
        delete preferences_lock;
 }
 
@@ -190,6 +193,7 @@ void Preferences::copy_from(Preferences *that)
        real_processors = that->real_processors;
        file_forking = that->file_forking;
        ffmpeg_early_probe = that->ffmpeg_early_probe;
+       ffmpeg_marker_indecies = that->ffmpeg_marker_indecies;
        warn_indecies = that->warn_indecies;
        renderfarm_nodes.remove_all_objects();
        renderfarm_ports.remove_all();
@@ -339,10 +343,11 @@ int Preferences::load_defaults(BC_Hash *defaults)
 
 
 
-       force_uniprocessor = defaults->get("FORCE_UNIPROCESSOR", 0);
-       file_forking = defaults->get("FILE_FORKING", 1);
-       ffmpeg_early_probe = defaults->get("FFMPEG_EARLY_PROBE", 0);
-       warn_indecies = defaults->get("WARN_INDECIES", 1);
+       force_uniprocessor = defaults->get("FORCE_UNIPROCESSOR", force_uniprocessor);
+       file_forking = defaults->get("FILE_FORKING", file_forking);
+       ffmpeg_early_probe = defaults->get("FFMPEG_EARLY_PROBE", ffmpeg_early_probe);
+       ffmpeg_marker_indecies = defaults->get("FFMPEG_MARKER_INDECIES", ffmpeg_marker_indecies);
+       warn_indecies = defaults->get("WARN_INDECIES", warn_indecies);
        use_brender = defaults->get("USE_BRENDER", use_brender);
        brender_fragment = defaults->get("BRENDER_FRAGMENT", brender_fragment);
        cache_size = defaults->get("CACHE_SIZE", cache_size);
@@ -440,6 +445,7 @@ int Preferences::save_defaults(BC_Hash *defaults)
        defaults->update("FORCE_UNIPROCESSOR", force_uniprocessor);
        defaults->update("FILE_FORKING", file_forking);
        defaults->update("FFMPEG_EARLY_PROBE", ffmpeg_early_probe);
+       defaults->update("FFMPEG_MARKER_INDECIES", ffmpeg_marker_indecies);
        defaults->update("WARN_INDECIES", warn_indecies);
        brender_asset->save_defaults(defaults, 
                "BRENDER_",
index 30ff9242dbe8bb092f6906d49337dde22cbbb848..a2829e7eea5bf2f600e4ac7db0832b59b90d9463 100644 (file)
@@ -101,6 +101,8 @@ public:
        int file_forking;
 // ffmpeg probes early/late during File::open_file read
        int ffmpeg_early_probe;
+// ffmpeg builds marker indecies as it builds idx files
+       int ffmpeg_marker_indecies;
        int warn_indecies;
 
 // Default positions for channels
index ffa2b2825e4b87b865200019be04a0bb97fc6722..c4c6f4b5cb0a4803141cf208dd4c09a8b2b2e384 100644 (file)
@@ -465,6 +465,7 @@ void Record::delete_index_file(Asset *asset)
 {
        IndexFile::delete_index(mwindow->preferences, asset, ".toc");
        IndexFile::delete_index(mwindow->preferences, asset, ".idx");
+       IndexFile::delete_index(mwindow->preferences, asset, ".mkr");
 }
 
 void Record::delete_batch()
index e2cdb52c0f5878a1037a78703d9816bbc0f91a9d..6833917e97da1c1835023122de16863d069c9aba 100644 (file)
@@ -46,7 +46,7 @@ RemoveFile::RemoveFile(const char *path,int autodelete)
 void RemoveFile::run()
 {
        run_lock.lock("RemoveFile::run_lock");
-printf("RemoveFile::run: deleting %s\n", file_path);
+//printf("RemoveFile::run: deleting %s\n", file_path);
        remove(file_path);
        run_lock.unlock();
 }
@@ -66,7 +66,7 @@ RemoveAll::RemoveAll(const char *path)
                else
                        RemoveFile::removeFileWait(fp);
        }
-printf("RemoveAll::deleting directory %s\n", path);
+//printf("RemoveAll::deleting directory %s\n", path);
        rmdir(path);
 }
 
index 3c439438b2363646479ade2a6b50fe6e0e881848..5f66b34102a5d96163242f9b815627101d5e4df7 100644 (file)
@@ -69,6 +69,7 @@ public:
                total = 0;
        }
        TYPE &last() { return values[total - 1]; }
+
        void set_array_delete() { dtype = d_array; }
        void set_free() { dtype = d_free; }
        int size() { return total; }
index 32547118e6514c29fd63d1b52b0884b7082fb3e0..21a91f71983e406bf2fc0fba9bfbf9436c2af41b 100644 (file)
@@ -139,10 +139,12 @@ BC_WindowBase::~BC_WindowBase()
        if( get_resources()->get_synchronous() && top_level->options & GLX_WINDOW ) {
                if( !glx_win ) {
 // NVIDIA library threading problem, XCloseDisplay SEGVs without this
+                       lock_window("BC_WindowBase::~BC_WindowBase:XDestroyWindow");
                        sync_lock("BC_WindowBase::~BC_WindowBase:XDestroyWindow");
                        glXMakeContextCurrent(top_level->display, 0, 0, 0);
                        XDestroyWindow(top_level->display, win);
                        sync_unlock();
+                       unlock_window();
                }
                else
                        get_resources()->get_synchronous()->delete_window(this);
index e28ec10b1725b45077fda2f79722550977f523a8..6e9d27f72261b62ce374af58dd43e8434dcad708 100644 (file)
@@ -84,7 +84,7 @@ const char *cmdl[] = {
  "rgb_floatp", "rgba_floatp",
 };
 
-void write_pbm(uint8_t *tp, int w, int h, const char *fmt, ...)
+void write_pgm(uint8_t *tp, int w, int h, const char *fmt, ...)
 {
   va_list ap;    va_start(ap, fmt);
   char fn[256];  vsnprintf(fn, sizeof(fn), fmt, ap);
@@ -97,7 +97,7 @@ void write_pbm(uint8_t *tp, int w, int h, const char *fmt, ...)
   }
 }
 
-void write_pgm(uint8_t *tp, int w, int h, const char *fmt, ...)
+void write_ppm(uint8_t *tp, int w, int h, const char *fmt, ...)
 {
   va_list ap;    va_start(ap, fmt);
   char fn[256];  vsnprintf(fn, sizeof(fn), fmt, ap);
index 552255a5b77ae3325dbc092dae7cc701dc5f7029..c3d068e0b3c867bfadd06572433bfa27b63c2d49 100644 (file)
@@ -266,16 +266,6 @@ int Thread::continue_thread()
        return 0;
 }
 
-bool Thread::exists()
-{
-       return tid != ((pthread_t)-1);
-}
-
-bool Thread::running()
-{
-       return exists() & ~finished;
-}
-
 int Thread::set_synchronous(int value)
 {
        this->synchronous = value != 0;
index ae607a38bc113839402a1d73626c9a8d5498a059..1eb86959e39a5369bd742405a767b2acb81a8e89 100644 (file)
@@ -37,9 +37,9 @@ static inline int gettid() { return syscall(SYS_gettid, 0, 0, 0); }
 
 class Thread
 {
-private:
        static void* entrypoint(void *parameters);
-       bool exists();           // tid exists
+       bool exists() { return tid != ((pthread_t)-1); }
+
 protected:
        virtual void run() = 0;
 public:
@@ -54,7 +54,8 @@ public:
        int enable_cancel();
        int disable_cancel();
        int get_cancel_enabled();
-       bool running();          // exists and not finished
+       bool running() { return exists() && !finished; }
+
        int get_synchronous();
        int set_synchronous(int value);
        int get_realtime();