//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);
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.
-
const char* Asset::construct_param(const char *param,
const char *prefix,
char *return_value)
-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");
#include "filexml.inc"
#include "indexable.h"
#include "indexfile.inc"
+#include "indexstate.inc"
#include "linklist.h"
#include "pluginserver.inc"
// Executed during index building only
- void update_index(Asset *asset);
int equivalent(Asset &asset,
int test_audio,
int test_video);
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();
int write_audio(FileXML *xml);
int write_video(FileXML *xml);
int write_index(FileXML *xml);
- int update_path(char *new_path);
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);
if(edl) edl->remove_user();
if( icon && !gui->protected_pixmap(icon) ) {
delete icon;
+ if( !plugin ) delete icon_vframe;
}
}
delete zoom_panel;
delete active;
delete inactive;
+ delete orig_mask_keyframe;
}
void CWindowGUI::create_objects()
// 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);
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);
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);
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);
#include "fileffmpeg.h"
#include "file.h"
#include "ffmpeg.h"
+#include "indexfile.h"
#include "libdv.h"
#include "libmjpeg.h"
#include "mainerror.h"
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 )
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)
if( ip >= lmt ) ip = bfr;
}
inp = ip;
+ hpos += len;
return len;
}
if( ip >= lmt ) ip = bfr;
}
inp = ip;
+ hpos += len;
return len;
}
}
-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;
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;
}
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;
{
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;
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;
sz = 0x10000;
long bsz = sz * nch;
bfr = new float[bsz];
- inp = outp = bfr;
lmt = bfr + bsz;
+ reset_history();
}
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;
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;
}
{
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)
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;
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 ) {
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;
}
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 ) {
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;
}
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;
}
}
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;
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;
}
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 ) {
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)
{
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;
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");
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;
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;
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;
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;
{
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;
}
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;
}
{
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;
}
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)
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];
{
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];
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;
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);
+ }
+}
+
#include "ffmpeg.inc"
#include "filebase.inc"
#include "fileffmpeg.inc"
+#include "indexstate.inc"
#include "mutex.h"
#include "thread.h"
#include "vframe.inc"
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();
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);
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; }
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);
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);
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;
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);
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;
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; }
#include "file.h"
#include "filempeg.h"
#include "language.h"
-#include "mwindow.inc"
#include "mainerror.h"
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);
#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)
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 ) {
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);
+}
#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>
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);
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
// 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;
#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)
{
}
char* FileXML::string()
{
- return (char *)buffer->pos();
+ return (char *)buffer->str();
+}
+
+long FileXML::length()
+{
+ return buffer->otell();
}
char* FileXML::read_text()
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;
}
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);
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);
int rewind();
char *get_data();
char *string();
+ long length();
XMLBuffer *buffer;
int coded;
char *output;
char left_delimiter, right_delimiter;
char filename[MAX_TITLE];
+ static const char *xml_header;
+ static const int xml_header_size;
};
#endif
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);
}
Indexable::~Indexable()
{
- delete index_state;
+ index_state->remove_user();
}
int Indexable::get_audio_channels()
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()
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;
// 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))
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);
int IndexFile::create_index(MainProgressBar *progress)
{
int result = 0;
-
SET_TRACE
- IndexState *index_state = get_state();
-
interrupt_flag = 0;
// open the source file
// 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
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;
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"));
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;
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;
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;
}
}
-
-
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;
{
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
// 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);
}
// 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
#include "file.inc"
#include "guicast.h"
#include "indexable.inc"
+#include "indexfile.inc"
#include "indexstate.inc"
#include "indexthread.inc"
#include "mainprogress.inc"
#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
*/
+#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)
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();
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;
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();
+}
#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
#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
#define INDEX_BUILDING 2
#define INDEX_TOOSMALL 3
+#define MARKERS_NOTTESTED 0
+#define MARKERS_READY 1
#endif
-
-
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++)
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);
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++)
delete output_lock[i];
delete input_lock[i];
}
-
- delete [] index_state->index_buffer;
- index_state->index_buffer = 0;
}
int IndexThread::start_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();
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);
}
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);
}
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;
}
-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);
}
}
-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);
//printf("MWindow::clean_indexes 2 %s\n", string2);
sprintf(ptr, ".toc");
remove(string2);
+ sprintf(ptr, ".mkr");
+ remove(string2);
}
}
// Erase file
IndexFile::delete_index(preferences, asset, ".toc");
IndexFile::delete_index(preferences, asset, ".idx");
+ IndexFile::delete_index(preferences, asset, ".mkr");
}
void MWindow::rebuild_indices()
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();
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__);
// __LINE__,
// current->index_state,
// nested_edl->index_state->index_status);
- current->index_state->copy_from(nested_edl->index_state);
+ current->update_index(nested_edl);
}
}
}
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;
PrefsFFMPEGEarlyProbe::~PrefsFFMPEGEarlyProbe()
{
}
+
int PrefsFFMPEGEarlyProbe::handle_event()
{
perf_prefs->pwindow->thread->preferences->ffmpeg_early_probe = get_value();
}
+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;
+}
+
+
BC_Title *master_rate;
PrefsFileForking *file_forking;
PrefsFFMPEGEarlyProbe *ffmpeg_early_probe;
+ PrefsFFMPEGMarkerIndecies *ffmpeg_marker_indecies;
};
PerformancePrefs *perf_prefs;
};
+class PrefsFFMPEGMarkerIndecies : public BC_CheckBox
+{
+public:
+ PrefsFFMPEGMarkerIndecies(PerformancePrefs *perf_prefs, int x, int y);
+ ~PrefsFFMPEGMarkerIndecies();
+
+ int handle_event();
+
+ PerformancePrefs *perf_prefs;
+};
+
class PrefsTrapSigSEGV;
class PrefsTrapSigINTR;
class PrefsFFMPEGEarlyProbe;
+class PrefsFFMPEGMarkerIndecies;
class PrefsFileForking;
class PrefsRenderFarm;
class PrefsRenderFarmConsolidate;
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;
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
Preferences::~Preferences()
{
brender_asset->Garbage::remove_user();
+ shbtn_prefs.remove_all_objects();
+ renderfarm_nodes.remove_all_objects();
delete preferences_lock;
}
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();
- 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);
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_",
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
{
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()
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();
}
else
RemoveFile::removeFileWait(fp);
}
-printf("RemoveAll::deleting directory %s\n", path);
+//printf("RemoveAll::deleting directory %s\n", path);
rmdir(path);
}
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; }
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);
"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);
}
}
-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);
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;
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:
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();