| 1 | /* |
| 2 | * serialize.c |
| 3 | * |
| 4 | * Copyright (C) Georg Martius - January 2013 |
| 5 | * georg dot martius at web dot de |
| 6 | * |
| 7 | * This file is part of vid.stab video stabilization library |
| 8 | * |
| 9 | * vid.stab is free software; you can redistribute it and/or modify |
| 10 | * it under the terms of the GNU General Public License, |
| 11 | * as published by the Free Software Foundation; either version 2, or |
| 12 | * (at your option) any later version. |
| 13 | * |
| 14 | * vid.stab is distributed in the hope that it will be useful, |
| 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 17 | * GNU General Public License for more details. |
| 18 | * |
| 19 | * You should have received a copy of the GNU General Public License |
| 20 | * along with GNU Make; see the file COPYING. If not, write to |
| 21 | * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. |
| 22 | * |
| 23 | */ |
| 24 | |
| 25 | #include <assert.h> |
| 26 | #include <string.h> |
| 27 | |
| 28 | #include "serialize.h" |
| 29 | #include "transformtype.h" |
| 30 | #include "transformtype_operations.h" |
| 31 | #include "motiondetect.h" |
| 32 | |
| 33 | const char* modname = "vid.stab - serialization"; |
| 34 | |
| 35 | |
| 36 | int storeLocalmotion(FILE* f, const LocalMotion* lm){ |
| 37 | return fprintf(f,"(LM %i %i %i %i %i %lf %lf)", lm->v.x,lm->v.y,lm->f.x,lm->f.y,lm->f.size, |
| 38 | lm->contrast, lm->match); |
| 39 | } |
| 40 | |
| 41 | /// restore local motion from file |
| 42 | LocalMotion restoreLocalmotion(FILE* f){ |
| 43 | LocalMotion lm; |
| 44 | char c; |
| 45 | if(fscanf(f,"(LM %i %i %i %i %i %lf %lf", &lm.v.x,&lm.v.y,&lm.f.x,&lm.f.y,&lm.f.size, |
| 46 | &lm.contrast, &lm.match) != 7) { |
| 47 | vs_log_error(modname, "Cannot parse localmotion!\n"); |
| 48 | return null_localmotion(); |
| 49 | } |
| 50 | while((c=fgetc(f)) && c!=')' && c!=EOF); |
| 51 | if(c==EOF){ |
| 52 | vs_log_error(modname, "Cannot parse localmotion missing ')'!\n"); |
| 53 | return null_localmotion(); |
| 54 | } |
| 55 | return lm; |
| 56 | } |
| 57 | |
| 58 | int vsStoreLocalmotions(FILE* f, const LocalMotions* lms){ |
| 59 | int len = vs_vector_size(lms); |
| 60 | int i; |
| 61 | fprintf(f,"List %i [",len); |
| 62 | for (i=0; i<len; i++){ |
| 63 | if(i>0) fprintf(f,","); |
| 64 | if(storeLocalmotion(f,LMGet(lms,i)) <= 0) return 0; |
| 65 | } |
| 66 | fprintf(f,"]"); |
| 67 | return 1; |
| 68 | } |
| 69 | |
| 70 | /// restores local motions from file |
| 71 | LocalMotions vsRestoreLocalmotions(FILE* f){ |
| 72 | LocalMotions lms; |
| 73 | int i; |
| 74 | char c; |
| 75 | int len; |
| 76 | vs_vector_init(&lms,0); |
| 77 | if(fscanf(f,"List %i [", &len) != 1) { |
| 78 | vs_log_error(modname, "Cannot parse localmotions list expect 'List len ['!\n"); |
| 79 | return lms; |
| 80 | } |
| 81 | if (len>0){ |
| 82 | vs_vector_init(&lms,len); |
| 83 | for (i=0; i<len; i++){ |
| 84 | if(i>0) while((c=fgetc(f)) && c!=',' && c!=EOF); |
| 85 | LocalMotion lm = restoreLocalmotion(f); |
| 86 | vs_vector_append_dup(&lms,&lm,sizeof(LocalMotion)); |
| 87 | } |
| 88 | } |
| 89 | if(len != vs_vector_size(&lms)){ |
| 90 | vs_log_error(modname, "Cannot parse the given number of localmotions!\n"); |
| 91 | return lms; |
| 92 | } |
| 93 | while((c=fgetc(f)) && c!=']' && c!=EOF); |
| 94 | if(c==EOF){ |
| 95 | vs_log_error(modname, "Cannot parse localmotions list missing ']'!\n"); |
| 96 | return lms; |
| 97 | } |
| 98 | return lms; |
| 99 | } |
| 100 | |
| 101 | int vsPrepareFile(const VSMotionDetect* md, FILE* f){ |
| 102 | if(!f) return VS_ERROR; |
| 103 | fprintf(f, "VID.STAB 1\n"); |
| 104 | fprintf(f, "# accuracy = %d\n", md->conf.accuracy); |
| 105 | fprintf(f, "# shakiness = %d\n", md->conf.shakiness); |
| 106 | fprintf(f, "# stepsize = %d\n", md->conf.stepSize); |
| 107 | fprintf(f, "# mincontrast = %f\n", md->conf.contrastThreshold); |
| 108 | return VS_OK; |
| 109 | } |
| 110 | |
| 111 | int vsWriteToFile(const VSMotionDetect* md, FILE* f, const LocalMotions* lms){ |
| 112 | if(!f || !lms) return VS_ERROR; |
| 113 | |
| 114 | if(fprintf(f, "Frame %i (", md->frameNum)>0 |
| 115 | && vsStoreLocalmotions(f,lms)>0 && fprintf(f, ")\n")) |
| 116 | return VS_OK; |
| 117 | else |
| 118 | return VS_ERROR; |
| 119 | } |
| 120 | |
| 121 | /// reads the header of the file and return the version number |
| 122 | int vsReadFileVersion(FILE* f){ |
| 123 | if(!f) return VS_ERROR; |
| 124 | int version; |
| 125 | if(fscanf(f, "VID.STAB %i\n", &version)!=1) |
| 126 | return VS_ERROR; |
| 127 | else return version; |
| 128 | } |
| 129 | |
| 130 | int vsReadFromFile(FILE* f, LocalMotions* lms){ |
| 131 | char c = fgetc(f); |
| 132 | if(c=='F') { |
| 133 | int num; |
| 134 | if(fscanf(f,"rame %i (", &num)!=1) { |
| 135 | vs_log_error(modname,"cannot read file, expect 'Frame num (...'"); |
| 136 | return VS_ERROR; |
| 137 | } |
| 138 | *lms = vsRestoreLocalmotions(f); |
| 139 | if(fscanf(f,")\n")<0) { |
| 140 | vs_log_error(modname,"cannot read file, expect '...)'"); |
| 141 | return VS_ERROR; |
| 142 | } |
| 143 | return num; |
| 144 | } else if(c=='#') { |
| 145 | char l[1024]; |
| 146 | if(fgets(l, sizeof(l), f)==0) return VS_ERROR; |
| 147 | return vsReadFromFile(f,lms); |
| 148 | } else if(c=='\n' || c==' ') { |
| 149 | return vsReadFromFile(f,lms); |
| 150 | } else if(c==EOF) { |
| 151 | return VS_ERROR; |
| 152 | } else { |
| 153 | vs_log_error(modname,"cannot read frame local motions from file, got %c (%i)", |
| 154 | c, (int) c); |
| 155 | return VS_ERROR; |
| 156 | } |
| 157 | } |
| 158 | |
| 159 | int vsReadLocalMotionsFile(FILE* f, VSManyLocalMotions* mlms){ |
| 160 | int version = vsReadFileVersion(f); |
| 161 | if(version<1) // old format or unknown |
| 162 | return VS_ERROR; |
| 163 | if(version>1){ |
| 164 | vs_log_error(modname,"Version of VID.STAB file too large: got %i, expect <= 1", |
| 165 | version); |
| 166 | return VS_ERROR; |
| 167 | } |
| 168 | assert(mlms); |
| 169 | // initial number of frames, but it will automatically be increaseed |
| 170 | vs_vector_init(mlms,1024); |
| 171 | int index; |
| 172 | int oldindex = 0; |
| 173 | LocalMotions lms; |
| 174 | while((index = vsReadFromFile(f,&lms)) != VS_ERROR){ |
| 175 | if(index > oldindex+1){ |
| 176 | vs_log_info(modname,"VID.STAB file: index of frames is not continuous %i -< %i", |
| 177 | oldindex, index); |
| 178 | } |
| 179 | if(index<1){ |
| 180 | vs_log_info(modname,"VID.STAB file: Frame number < 1 (%i)", index); |
| 181 | } else { |
| 182 | vs_vector_set_dup(mlms,index-1,&lms, sizeof(LocalMotions)); |
| 183 | } |
| 184 | oldindex=index; |
| 185 | } |
| 186 | return VS_OK; |
| 187 | } |
| 188 | |
| 189 | |
| 190 | /** |
| 191 | * vsReadOldTransforms: read transforms file (Deprecated format) |
| 192 | * The format is as follows: |
| 193 | * Lines with # at the beginning are comments and will be ignored |
| 194 | * Data lines have 5 columns seperated by space or tab containing |
| 195 | * time, x-translation, y-translation, alpha-rotation, extra |
| 196 | * where time and extra are integers |
| 197 | * and the latter is unused at the moment |
| 198 | * |
| 199 | * Parameters: |
| 200 | * f: file description |
| 201 | * trans: place to store the transforms |
| 202 | * Return value: |
| 203 | * number of transforms read |
| 204 | * Preconditions: f is opened |
| 205 | */ |
| 206 | int vsReadOldTransforms(const VSTransformData* td, FILE* f , VSTransformations* trans) |
| 207 | { |
| 208 | char l[1024]; |
| 209 | int s = 0; |
| 210 | int i = 0; |
| 211 | int ti; // time (ignored) |
| 212 | VSTransform t; |
| 213 | |
| 214 | while (fgets(l, sizeof(l), f)) { |
| 215 | t = null_transform(); |
| 216 | if (l[0] == '#') |
| 217 | continue; // ignore comments |
| 218 | if (strlen(l) == 0) |
| 219 | continue; // ignore empty lines |
| 220 | // try new format |
| 221 | if (sscanf(l, "%i %lf %lf %lf %lf %i", &ti, &t.x, &t.y, &t.alpha, |
| 222 | &t.zoom, &t.extra) != 6) { |
| 223 | if (sscanf(l, "%i %lf %lf %lf %i", &ti, &t.x, &t.y, &t.alpha, |
| 224 | &t.extra) != 5) { |
| 225 | vs_log_error(td->conf.modName, "Cannot parse line: %s", l); |
| 226 | return 0; |
| 227 | } |
| 228 | t.zoom=0; |
| 229 | } |
| 230 | |
| 231 | if (i>=s) { // resize transform array |
| 232 | if (s == 0) |
| 233 | s = 256; |
| 234 | else |
| 235 | s*=2; |
| 236 | /* vs_log_info(td->modName, "resize: %i\n", s); */ |
| 237 | trans->ts = vs_realloc(trans->ts, sizeof(VSTransform)* s); |
| 238 | if (!trans->ts) { |
| 239 | vs_log_error(td->conf.modName, "Cannot allocate memory" |
| 240 | " for transformations: %i\n", s); |
| 241 | return 0; |
| 242 | } |
| 243 | } |
| 244 | trans->ts[i] = t; |
| 245 | i++; |
| 246 | } |
| 247 | trans->len = i; |
| 248 | |
| 249 | return i; |
| 250 | } |
| 251 | |
| 252 | |
| 253 | // t = vsSimpleMotionsToTransform(md, &localmotions); |
| 254 | |
| 255 | |
| 256 | /* |
| 257 | * Local variables: |
| 258 | * c-file-style: "stroustrup" |
| 259 | * c-file-offsets: ((case-label . *) (statement-case-intro . *)) |
| 260 | * indent-tabs-mode: nil |
| 261 | * c-basic-offset: 2 t |
| 262 | * End: |
| 263 | * |
| 264 | * vim: expandtab shiftwidth=2: |
| 265 | */ |