8 #include "../cinelerra/mediadb.inc"
14 static inline int clip(int v, int mn, int mx)
16 return v<mn ? mn : v>mx ? mx : v;
19 void write_pbm(uint8_t *tp, int w, int h, const char *fmt, ...)
21 va_list ap; va_start(ap, fmt);
22 char fn[256]; vsnprintf(fn, sizeof(fn), fmt, ap);
24 FILE *fp = !strcmp(fn,"-") ? stdout : fopen(fn,"w");
26 fprintf(fp,"P5\n%d %d\n255\n",w,h);
32 void pbm_diff(uint8_t *ap, uint8_t *bp, int w, int h, const char *fmt, ...)
34 va_list va; va_start(va, fmt);
35 char fn[256]; vsnprintf(fn, sizeof(fn), fmt, va);
37 FILE *fp = !strcmp(fn,"-") ? stdout : fopen(fn,"w");
40 uint8_t dat[sz], *dp = dat;
41 for( int i=sz; --i>=0; ++dp,++ap,++bp ) *dp = clip(*ap-*bp+128, 0 ,255);
42 fprintf(fp,"P5\n%d %d\n255\n",w,h);
48 int verify_clips(uint8_t *ap,int asz, double afr,
49 uint8_t *bp, int bsz, double bfr,
50 double &ofs, double &error)
52 double atm = asz/afr, btm = bsz/bfr, lmt = fmin(atm, btm) / 2;
53 if( lmt > 8 ) lmt = 8;
54 if( fabs(atm - btm) > lmt ) return 0;
55 double arate, brate, fr; int margin;
57 arate = 1; brate = bfr / afr;
58 fr = afr; margin = afr + 0.5;
61 arate = afr / bfr; brate = 1;
62 fr = bfr; margin = bfr + 0.5;
64 double *awt = (double *)ap, *bwt = (double *)bp;
65 double best = 1e100; int ii = -1;
66 for( int i=-margin; i<=margin; ++i ) {
67 int aofs = i < 0 ? 0 : i*arate + 0.5;
68 int bofs = i < 0 ? -i*brate + 0.5 : 0;
69 double err = 0; int n = 0;
71 int ai = aofs + n*arate + 0.5;
72 if( ai >= asz ) break;
73 int bi = bofs + n*brate + 0.5;
74 if( bi >= bsz ) break;
75 err += fabs(awt[ai] - bwt[bi]);
78 if( err < best ) { best = err; ii = i; }
80 ofs = ii / fr; error = best;
81 if( best >= MEDIA_WEIGHT_ERRLMT ) return 0;
85 int *load_frames(theDb &db, int clip_id, int no, int len)
87 int *fp = new int[len], first = no;
88 for( int i=len; --i>=0; ) fp[i] = -1;
89 int ret = TimelineLoc::ikey_Sequences(db.timeline,clip_id,no).Locate();
91 for( int i=0; i<len; ++i,++no ) {
92 if( (int)db.timeline.Clip_id() != clip_id ) break;
93 int next = db.timeline.Sequence_no();
95 // printf("seqno skipped in clip %d from %d to %d\n",clip_id,no,next);
99 if( k >= 0 && k < len ) fp[k] = db.timeline.Frame_id();
100 if( TimelineLoc::rkey_Sequences(db.timeline).Next() ) break;
104 printf("cant access timeline of clip %d\n",clip_id);
108 int64_t media_weight(uint8_t *dat, int sz)
111 for( int i=sz; --i>=0; ++dat ) wt += *dat;
115 int64_t media_cmpr(uint8_t *ap, uint8_t *bp, int sz)
118 for( int i=sz; --i>=0; ++ap,++bp ) v += fabs(*ap-*bp);
122 int fix_err(theDb &db, double &err, double ofs,
123 int aid, int *afp, int asz, double afr,
124 int bid, int *bfp, int bsz, double bfr)
128 arate = 1; brate = bfr / afr;
131 arate = afr / bfr; brate = 1;
133 int aofs = ofs < 0 ? 0 : ofs*afr + 0.5;
134 int bofs = ofs < 0 ? -ofs*bfr + 0.5 : 0;
135 int n = 0, fno = 0; int votes = 0;
137 int ai = aofs + fno*arate + 0.5;
138 if( ai >= asz ) break;
139 int bi = bofs + fno*brate + 0.5;
140 if( bi >= bsz ) break;
141 Video_frameLoc aframe(db.video_frame);
142 Video_frameLoc bframe(db.video_frame);
143 if( afp[ai] < 0 || bfp[bi] < 0 ) {
144 // printf("missing prefix frame %d %d/%d in clip %d/%d\n",
145 // n, afp[ai], bfp[bi], aid, bid);
148 if( aframe.FindId(afp[ai]) ) {
149 printf("cant access prefix frame %d (id %d) in clip %d\n",
150 ai, afp[ai], aid); continue;
152 if( bframe.FindId(bfp[bi]) ) {
153 printf("cant access prefix frame %d (id %d) in clip %d\n",
154 bi, bfp[bi], bid); continue;
156 int w=80, h=45, sfrm_sz = w*h;
157 int64_t v = media_cmpr(aframe._Frame_data(), bframe._Frame_data(), sfrm_sz);
158 if( v/3600 < MEDIA_SEARCH_ERRLMT ) ++votes;
159 //printf("%d %ld(%d,%d)\n", n, v, afp[ai], bfp[bi]);
161 uint8_t *adat = aframe._Frame_data(), *bdat = bframe._Frame_data();
162 write_pbm(adat,w,h,"%s/a%05d.pbm",diff_path,afp[ai]);
163 write_pbm(bdat,w,h,"%s/b%05d.pbm",diff_path,bfp[bi]);
164 pbm_diff(adat,bdat,80,45,"%s/da%05d-b%05d.pbm",diff_path,afp[ai],bfp[bi]);
172 int verify_frames(theDb &db, int aid, int bid, double ofs)
174 int *apfx=0, *asfx=0, *bpfx=0, *bsfx=0;
175 int apsz=0, assz=0, bpsz=0, bssz=0, alen=0, blen=0, afrm=0, bfrm=0;
176 double afr = 1, bfr = 1;
177 if( !db.clip_set.FindId(aid) ) {
178 apsz = db.clip_set.Prefix_size();
179 assz = db.clip_set.Suffix_size();
180 alen = db.clip_set.Frames();
181 apfx = load_frames(db, aid, 0, apsz);
182 asfx = load_frames(db, aid, alen-assz, assz);
183 afr = db.clip_set.Framerate();
184 afrm = db.clip_set.Frames();
187 printf("cant open -a- clip %d\n",aid);
190 if( !db.clip_set.FindId(bid) ) {
191 bpsz = db.clip_set.Prefix_size();
192 bssz = db.clip_set.Suffix_size();
193 blen = db.clip_set.Frames();
194 bpfx = load_frames(db, bid, 0, bpsz);
195 bsfx = load_frames(db, bid, blen-bssz, bssz);
196 bfr = db.clip_set.Framerate();
197 bfrm = db.clip_set.Frames();
200 printf("cant open -b- clip %d\n",bid);
203 //printf("afrm %d, bfrm %d ",afrm, bfrm);
205 int pn = fix_err(db, perr, ofs, aid, apfx, apsz, afr, bid, bpfx, bpsz, bfr);
208 ofs -= afrm/afr-bfrm/bfr;
209 int sn = fix_err(db, serr, ofs, aid, asfx, assz, afr, bid, bsfx, bssz, bfr);
210 printf(" err %0.3f/%0.3f #%d+%d=%d\n", perr/(pn*80*45),serr/(sn*80*45), pn,sn,pn+sn);
219 double avg_wt(uint8_t *wp, int sz)
221 double *wt = (double *)wp;
224 for( int i=sz; --i>=0; ++wt ) v += *wt;
230 int main(int ac, char **av)
232 int ret; setbuf(stdout,0);
235 //db.access(av[1], 34543, 0);
236 if( !db.opened() || db.error() ) exit(1);
237 if( ac > 2 ) curr_id = atoi(av[2]);
238 if( ac > 3 ) next_id = atoi(av[3]);
239 if( ac > 4 ) diff_path = av[4];
240 if( curr_id >= 0 && next_id >= 0 ) {
241 Clip_setLoc curr(db.clip_set);
242 if( (ret=curr.FindId(curr_id)) ) {
243 printf("cant access clip %d\n", curr_id);
246 Clip_setLoc next(db.clip_set);
247 if( (ret=next.FindId(next_id)) ) {
248 printf("cant access clip %d\n", next_id);
251 double awt = curr.Average_weight();
252 double bwt = next.Average_weight();
253 double error=-1, ofs=-1;
254 int bias = awt - bwt;
255 verify_clips(curr._Weights(),curr.Frames(),curr.Framerate(),
256 next._Weights(), next.Frames(), next.Framerate(), ofs, error);
257 printf("dupl a=%4d(%0.2f)-%0.2f b=%4d(%0.2f)-%0.2f %s%d err=%0.3f ofs=%0.5f ",
258 curr.id(), curr.Framerate(),curr.Frames()/curr.Framerate(),
259 next.id(), next.Framerate(), next.Frames()/next.Framerate(),
260 bias >= 0 ? "+" : "", bias, error, ofs);
261 verify_frames(db, curr.id(), next.id(), ofs);
264 Clip_setLoc curr(db.clip_set);
266 if( !(ret=curr.FirstId(curr_loc)) ) {
268 Clip_setLoc next(curr);
269 Db::pgRef next_loc = curr_loc;
270 double awt = curr.Average_weight();
271 while( !next.NextId(next_loc) ) {
272 double error=-1, ofs =-1;
273 double bwt = next.Average_weight();
274 int bias = awt - bwt;
275 if( fabs(bias) > 10 ) continue;
276 if( verify_clips(curr._Weights(),curr.Frames(),curr.Framerate(),
277 next._Weights(), next.Frames(), next.Framerate(), ofs, error) ) {
278 printf("dupl a=%4d(%0.2f)-%0.2f b=%4d(%0.2f)-%0.2f %s%d err=%0.3f ofs=%0.3f ",
279 curr.id(), curr.Framerate(),curr.Frames()/curr.Framerate(),
280 next.id(), next.Framerate(), next.Frames()/next.Framerate(),
281 bias >= 0 ? "+" : "", bias, error, ofs);
282 verify_frames(db, curr.id(), next.id(), ofs);
286 } while( !(ret=curr.NextId(curr_loc)) );