~josejuan-sanchez/esajpip/debian

« back to all changes in this revision

Viewing changes to src/jpeg2000/file_manager.cc

  • Committer: José Juan Sánchez Hernández
  • Date: 2013-04-02 18:14:26 UTC
  • Revision ID: josejuan.sanchez@gmail.com-20130402181426-07xn3djblburck53
Version for Debian

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#include "file_manager.h"
 
2
#include "trace.h"
 
3
 
 
4
 
 
5
namespace jpeg2000
 
6
{
 
7
 
 
8
  using namespace std;
 
9
  using namespace data;
 
10
 
 
11
 
 
12
  #define EOC_MARKER 0xFFD9
 
13
  #define SOC_MARKER 0xFF4F
 
14
  #define SIZ_MARKER 0xFF51
 
15
  #define COD_MARKER 0xFF52
 
16
  #define SOT_MARKER 0xFF90
 
17
  #define PLT_MARKER 0xFF58
 
18
  #define SOD_MARKER 0xFF93
 
19
 
 
20
  #define JP2C_BOX_ID 0x6A703263
 
21
  #define XML__BOX_ID 0x786D6C20
 
22
  #define ASOC_BOX_ID 0x61736F63
 
23
  #define NLST_BOX_ID 0x6E6C7374
 
24
  #define JPCH_BOX_ID 0x6A706368
 
25
  #define FTBL_BOX_ID 0x6674626C
 
26
  #define DBTL_BOX_ID 0x6474626C
 
27
  #define URL__BOX_ID 0x75726C20
 
28
  #define FLST_BOX_ID 0x666C7374
 
29
 
 
30
 
 
31
  string FileManager::GetCacheFileName(const string& path_image_file)
 
32
  {
 
33
    string name_cache_file;
 
34
 
 
35
    size_t begin_pos = 0;
 
36
    while (!isalpha(path_image_file[begin_pos]))
 
37
      begin_pos++;
 
38
 
 
39
    name_cache_file=path_image_file.substr(begin_pos,path_image_file.size()-begin_pos);
 
40
 
 
41
    // Replace "." with "_"
 
42
    for (size_t j; (j = name_cache_file.find(".")) != string::npos;)
 
43
        name_cache_file.replace(j, 1, "_");
 
44
 
 
45
    // Replace "/" with "_"
 
46
    for (size_t j; (j = name_cache_file.find("/")) != string::npos;)
 
47
        name_cache_file.replace(j, 1, "_");
 
48
 
 
49
    // Add the file extension ".cache"
 
50
    //name_cache_file+=".cache";
 
51
 
 
52
    return name_cache_file;
 
53
  }
 
54
 
 
55
  bool FileManager::ExistCacheImage(const string& path_image_file, string *path_cache_file)
 
56
  {
 
57
    // Get the path cache file
 
58
    *path_cache_file = cache_dir_ + GetCacheFileName(path_image_file) + ".cache";
 
59
 
 
60
    struct stat cache_att;
 
61
 
 
62
    // Cache file exists
 
63
    if (stat(path_cache_file->c_str(), &cache_att) == 0)
 
64
    {
 
65
      // Get last modification dates of image and cache files
 
66
      struct stat file_att;
 
67
      stat(path_image_file.c_str(), &file_att);
 
68
 
 
69
      // Check if last modification date of image file is lower than
 
70
      // last modification date of cache file
 
71
      if (file_att.st_mtime < cache_att.st_mtime) return true;
 
72
    }
 
73
 
 
74
    return false;
 
75
  }
 
76
 
 
77
  bool FileManager::ReadImage(const string& name_image_file, ImageInfo *image_info)
 
78
  {
 
79
    bool res = true;
 
80
    string path_cache_file;
 
81
 
 
82
    // Cache file does not exist or it is not updated
 
83
    if (!ExistCacheImage(name_image_file, &path_cache_file))
 
84
    {
 
85
      File f;
 
86
      // Get file extension
 
87
      string extension = "";
 
88
      size_t pos = name_image_file.find_last_of(".");
 
89
      if (pos != string::npos) extension = name_image_file.substr(pos);
 
90
 
 
91
      // J2C image
 
92
      if (extension.compare(".j2c") == 0)
 
93
      {
 
94
        image_info->codestreams.push_back(CodestreamIndex());
 
95
 
 
96
        CodingParameters *cp = &image_info->coding_parameters;
 
97
        CodestreamIndex *ci = &image_info->codestreams.back();
 
98
        if (!f.OpenForReading(name_image_file.c_str()))
 
99
        {
 
100
                ERROR("Impossible to open file: '" << name_image_file << "'...");
 
101
                return false;
 
102
        }
 
103
        res = res && ReadCodestream(f, cp, ci);
 
104
        f.Close();
 
105
      }
 
106
      // JP2 image
 
107
      else if (extension.compare(".jp2") == 0)
 
108
      {
 
109
        image_info->codestreams.push_back(CodestreamIndex());
 
110
 
 
111
        if (!f.OpenForReading(name_image_file.c_str()))
 
112
        {
 
113
                ERROR("Impossible to open file: '" << name_image_file << "'...");
 
114
            return false;
 
115
        }
 
116
        res = res && ReadJP2(f, image_info);
 
117
        f.Close();
 
118
      }
 
119
      // JPX image
 
120
      else if (extension.compare(".jpx") == 0)
 
121
      {
 
122
        if (!f.OpenForReading(name_image_file.c_str()))
 
123
        {
 
124
                ERROR("Impossible to open file: '" << name_image_file << "'...");
 
125
                return false;
 
126
        }
 
127
        res = res && ReadJPX(f, image_info);
 
128
        f.Close();
 
129
      }
 
130
      else
 
131
      {
 
132
        ERROR("File type not supported...");
 
133
        return false;
 
134
      }
 
135
      // Serialize the info of the image in a cache file
 
136
      struct stat cache_dir_stat;
 
137
      if (stat(cache_dir_.c_str(), &cache_dir_stat)==0) res = res && OutputStream().Open(path_cache_file.c_str()).Serialize(*image_info);
 
138
    }
 
139
    // Cache file is updated
 
140
    else
 
141
    {
 
142
      // Get info of the image
 
143
      res = res && InputStream().Open(path_cache_file.c_str()).Serialize(*image_info);
 
144
    }
 
145
 
 
146
    return res;
 
147
  }
 
148
 
 
149
  bool FileManager::ReadCodestream(const File& file, CodingParameters *params, CodestreamIndex *index)
 
150
  {
 
151
    bool res = true;
 
152
 
 
153
    // Get markers
 
154
    bool plts = false;
 
155
    uint16_t value = 0;
 
156
 
 
157
    while (res = res && file.ReadReverse(&value), res && (value != EOC_MARKER))
 
158
    {
 
159
      switch (value)
 
160
      {
 
161
        case SOC_MARKER:
 
162
          TRACE("SOC marker...");
 
163
          index->header.offset = file.GetOffset() - 2;
 
164
          break;
 
165
 
 
166
        case SIZ_MARKER:
 
167
          TRACE("SIZ marker...");
 
168
          res = res && ReadSIZMarker(file, params);
 
169
          break;
 
170
 
 
171
        case COD_MARKER:
 
172
          TRACE("COD marker...");
 
173
          res = res && ReadCODMarker(file, params);
 
174
          break;
 
175
 
 
176
        case SOT_MARKER:
 
177
          TRACE("SOT marker...");
 
178
          res = res && ReadSOTMarker(file, index);
 
179
          break;
 
180
 
 
181
        case PLT_MARKER:
 
182
          TRACE("PLT marker...");
 
183
          res = res && ReadPLTMarker(file, index);
 
184
          if (res) plts = true;
 
185
          break;
 
186
 
 
187
        case SOD_MARKER:
 
188
          TRACE("SOD marker...");
 
189
          res = res && ReadSODMarker(file, index);
 
190
          break;
 
191
 
 
192
        default:
 
193
          res = res && file.ReadReverse(&value) && file.Seek(value - 2, SEEK_CUR);
 
194
      }
 
195
    }
 
196
 
 
197
    // Check if the image has been read in a right way
 
198
    if (value == EOC_MARKER)
 
199
    {
 
200
      // Check if the image has PLT marker
 
201
      if (plts) return true;
 
202
      else
 
203
      {
 
204
        ERROR("The code-stream does not include any PLT marker");
 
205
        return false;
 
206
      }
 
207
    }
 
208
    else
 
209
    {
 
210
      ERROR("The code-stream does not end with an EOC marker");
 
211
      return false;
 
212
    }
 
213
  }
 
214
 
 
215
  bool FileManager::ReadSIZMarker(const File& file, CodingParameters *params)
 
216
  {
 
217
    bool res = true;
 
218
    // To jump Lsiz, CA
 
219
    res = res && file.Seek(4, SEEK_CUR);
 
220
    // Get image height and width
 
221
    uint32_t FE[4];
 
222
    for (int i = 0; i < 4; i++)
 
223
      res = res && file.ReadReverse(&FE[i]);
 
224
    // height=F1-E1
 
225
    // width=F2-E2
 
226
    params->size = Size(FE[0] - FE[2], FE[1] - FE[3]);
 
227
    // Get T2, T1, omegaT2, omegaT1
 
228
    uint32_t tiling[4];
 
229
    for (int i = 0; i < 4; i++)
 
230
      res = res && file.ReadReverse(&tiling[i]);
 
231
    // Get number of components
 
232
    uint16_t num_components;
 
233
    res = res && file.ReadReverse(&num_components);
 
234
    params->num_components = num_components;
 
235
    // To jump to the end of the marker
 
236
    res = res && file.Seek(3 * num_components, SEEK_CUR);
 
237
 
 
238
    return res;
 
239
  }
 
240
 
 
241
  bool FileManager::ReadCODMarker(const File& file, CodingParameters *params)
 
242
  {
 
243
    bool res = true;
 
244
    // Get CS0 parameter
 
245
    uint8_t cs_buf;
 
246
    res = res && file.Seek(2, SEEK_CUR) && file.ReadReverse(&cs_buf);
 
247
    // Get progression order
 
248
    uint8_t progression;
 
249
    res = res && file.ReadReverse(&progression);
 
250
    params->progression = progression;
 
251
    // Get number of quality layers
 
252
    uint16_t quality_layers;
 
253
    // To jump MC
 
254
    res = res && file.ReadReverse(&quality_layers) && file.Seek(1, SEEK_CUR);
 
255
    params->num_layers = quality_layers;
 
256
    // Get transform levels
 
257
    uint8_t transform_levels;
 
258
    // To jump 4 bytes (ECB2,ECB1,MS,WT)
 
259
    res = res && file.ReadReverse(&transform_levels) && file.Seek(4, SEEK_CUR);
 
260
    params->num_levels = transform_levels;
 
261
    // Get precint sizes for each resolution
 
262
    int height, width;
 
263
    uint8_t size_precinct;
 
264
    params->precinct_size.clear();
 
265
    for (int i = 0; i <= params->num_levels; i++)
 
266
    {
 
267
      if (cs_buf & 1)
 
268
      {
 
269
        res = res && file.ReadReverse(&size_precinct);
 
270
        height = 1L << ((size_precinct & 0xF0) >> 4);
 
271
        width = 1L << (size_precinct & 0x0F);
 
272
        params->precinct_size.push_back(Size(width, height));
 
273
      }
 
274
      else
 
275
      {
 
276
        height = ceil((double) params->size.y / (1L << i));
 
277
        width = ceil((double) params->size.x / (1L << i));
 
278
        params->precinct_size.insert(params->precinct_size.begin(), Size(width, height));
 
279
      }
 
280
    }
 
281
    return res;
 
282
  }
 
283
 
 
284
  bool FileManager::ReadSOTMarker(const File& file, CodestreamIndex *index)
 
285
  {
 
286
    bool res = true;
 
287
    // Get offset of the codestream header
 
288
    if (index->header.length == 0) index->header.length = file.GetOffset() - 2 - index->header.offset;
 
289
    // Get Ltp
 
290
    uint32_t ltp;
 
291
    // To jump Lsot, it, itp, ntp
 
292
    res = res && file.Seek(4, SEEK_CUR) && file.ReadReverse(&ltp) && file.Seek(2, SEEK_CUR);
 
293
    index->packets.push_back(FileSegment(file.GetOffset(), ltp - 12));
 
294
    return res;
 
295
  }
 
296
 
 
297
  bool FileManager::ReadPLTMarker(const File& file, CodestreamIndex *index)
 
298
  {
 
299
    bool res = true;
 
300
    // Get PLT offset
 
301
    uint64_t PLT_offset = file.GetOffset() + 3;
 
302
    // Get Lplt
 
303
    uint16_t lplt;
 
304
    res = res && file.ReadReverse(&lplt);
 
305
    res = res && file.Seek(lplt - 2, SEEK_CUR);
 
306
    // PLT marker length = Lplt - 3 (2 bytes Lplt and 1 byte iplt)
 
307
    index->PLT_markers.push_back(FileSegment(PLT_offset, lplt - 3));
 
308
    return res;
 
309
  }
 
310
 
 
311
  bool FileManager::ReadSODMarker(const File& file, CodestreamIndex *index)
 
312
  {
 
313
    bool res = true;
 
314
    // Get packets info
 
315
    FileSegment& fs = index->packets.back();
 
316
    fs.length = fs.length - (file.GetOffset() - fs.offset);
 
317
    fs.offset = file.GetOffset();
 
318
    res = res && file.Seek(fs.length, SEEK_CUR);
 
319
    return res;
 
320
  }
 
321
 
 
322
  bool FileManager::ReadBoxHeader(const File &file, uint32_t *type_box, uint64_t *length_box)
 
323
  {
 
324
    bool res = true;
 
325
    // Get L, if it is not 0 or 1, then box length is L
 
326
    uint32_t L;
 
327
    res = res && file.ReadReverse(&L);
 
328
    *length_box = L - 8;
 
329
    // Get T (box type)
 
330
    uint32_t T;
 
331
    res = res && file.ReadReverse(&T);
 
332
    *type_box = T;
 
333
    // XL indicates the box length
 
334
    if (L == 1)
 
335
    {
 
336
      uint64_t XL;
 
337
      res = res && file.ReadReverse(&XL);
 
338
      *length_box = XL - 16;
 
339
    }
 
340
    // Box length = eof_offset - offset
 
341
    else if (L == 0)
 
342
    {
 
343
      *length_box = file.GetSize() - file.GetOffset();
 
344
    }
 
345
    return res;
 
346
  }
 
347
 
 
348
  bool FileManager::ReadJP2(const File& file, ImageInfo *image_info)
 
349
  {
 
350
    bool res = true;
 
351
    // Get boxes
 
352
    uint32_t type_box;
 
353
    uint64_t length_box;
 
354
    int pini=0, plen=0, pini_box=0, plen_box=0;
 
355
    //int metadata_bin=1;
 
356
 
 
357
    while (file.GetOffset() != file.GetSize() && res)
 
358
    {
 
359
      pini_box=file.GetOffset();
 
360
      plen = pini_box-pini;
 
361
      res = res && ReadBoxHeader(file, &type_box, &length_box);
 
362
      plen_box=file.GetOffset()-pini_box;
 
363
      switch (type_box)
 
364
      {
 
365
        case JP2C_BOX_ID:
 
366
          TRACE("JP2C box...");
 
367
          image_info->meta_data.meta_data.push_back(FileSegment(pini,plen));
 
368
          res = res && ReadCodestream(file, &image_info->coding_parameters, &image_info->codestreams.back());
 
369
          image_info->meta_data.place_holders.push_back(PlaceHolder(image_info->codestreams.size()-1, true, FileSegment(pini_box, plen_box), length_box));
 
370
          pini=file.GetOffset();
 
371
          plen=0;
 
372
          break;
 
373
 
 
374
        /*case XML__BOX_ID:
 
375
          TRACE("XML box...");
 
376
          image_info->meta_data.meta_data.push_back(FileSegment(pini,plen));
 
377
          // Get meta_data info
 
378
          res = res && file.Seek(length_box, SEEK_CUR);
 
379
          image_info->meta_data.place_holders.push_back(PlaceHolder(metadata_bin, false, FileSegment(pini_box, plen_box), length_box));
 
380
          metadata_bin++;
 
381
          pini=file.GetOffset();
 
382
          plen=0;
 
383
          break;*/
 
384
 
 
385
        default:
 
386
          res = res && file.Seek(length_box, SEEK_CUR);
 
387
      }
 
388
    }
 
389
    image_info->meta_data.meta_data.push_back(FileSegment(pini,file.GetOffset()-pini));
 
390
    return res;
 
391
  }
 
392
 
 
393
  bool FileManager::ReadJPX(const File& file, ImageInfo *image_info)
 
394
  {
 
395
    bool res = true;
 
396
    // Get boxes
 
397
    uint32_t type_box;
 
398
    uint64_t length_box;
 
399
    string path_file;
 
400
    uint16_t data_reference;
 
401
    vector<uint16_t> v_data_reference;
 
402
    vector<string> v_path_file;
 
403
    int pini=0, plen=0, pini_box=0, plen_box=0, pini_ftbl, plen_ftbl;
 
404
    //int metadata_bin=1;
 
405
    int num_flst;
 
406
 
 
407
    while (file.GetOffset() != file.GetSize() && res)
 
408
    {
 
409
      pini_box=file.GetOffset();
 
410
      plen = pini_box-pini;
 
411
      res = res && ReadBoxHeader(file, &type_box, &length_box);
 
412
      plen_box=file.GetOffset()-pini_box;
 
413
      switch (type_box)
 
414
      {
 
415
        case JPCH_BOX_ID:
 
416
          TRACE("JPCH box...");
 
417
          image_info->codestreams.push_back(CodestreamIndex());
 
418
          break;
 
419
        case JP2C_BOX_ID:
 
420
          TRACE("JP2C box...");
 
421
          image_info->meta_data.meta_data.push_back(FileSegment(pini,plen));
 
422
          res = res && ReadCodestream(file, &image_info->coding_parameters, &image_info->codestreams.back());
 
423
          image_info->meta_data.place_holders.push_back(PlaceHolder(image_info->codestreams.size()-1, true, FileSegment(pini_box, plen_box), length_box));
 
424
          pini=file.GetOffset();
 
425
          plen=0;
 
426
          break;
 
427
        /*case ASOC_BOX_ID:
 
428
          TRACE("ASOC box...");
 
429
          image_info->meta_data.meta_data.push_back(FileSegment(pini,plen));
 
430
          res = res && file.Seek(length_box, SEEK_CUR);
 
431
          image_info->meta_data.place_holders.push_back(PlaceHolder(metadata_bin, false, FileSegment(pini_box, plen_box), length_box));
 
432
          metadata_bin++;
 
433
          pini=file.GetOffset();
 
434
          plen=0;
 
435
          break;
 
436
        case XML__BOX_ID:
 
437
          TRACE("XML box...");
 
438
          image_info->meta_data.meta_data.push_back(FileSegment(pini,plen));
 
439
          res = res && file.Seek(length_box, SEEK_CUR);
 
440
          image_info->meta_data.place_holders.push_back(PlaceHolder(metadata_bin, false, FileSegment(pini_box, plen_box), length_box));
 
441
          metadata_bin++;
 
442
          pini=file.GetOffset();
 
443
          plen=0;
 
444
          break;*/
 
445
        case FTBL_BOX_ID:
 
446
          TRACE("FTBL box...");
 
447
          image_info->meta_data.meta_data.push_back(FileSegment(pini,plen));
 
448
          num_flst=0;
 
449
          pini_ftbl=pini_box;
 
450
          plen_ftbl=plen_box;
 
451
          break;
 
452
        case FLST_BOX_ID:
 
453
          TRACE("FLST box...");
 
454
          res = res && ReadFlstBox(file, length_box, &data_reference);
 
455
          if (num_flst)
 
456
                  image_info->meta_data.meta_data.push_back(FileSegment(0,0));
 
457
          num_flst++;
 
458
          image_info->meta_data.place_holders.push_back(PlaceHolder(v_data_reference.size(), true, FileSegment(pini_ftbl,plen_ftbl), 0));
 
459
          v_data_reference.push_back(data_reference);
 
460
          pini=file.GetOffset();
 
461
          plen=0;
 
462
          break;
 
463
        case DBTL_BOX_ID:
 
464
          TRACE("DBTL box...");
 
465
          res = res && file.Seek(2, SEEK_CUR);
 
466
          break;
 
467
        case URL__BOX_ID:
 
468
          TRACE("URL box...");
 
469
          // Add the paths of the hyperlinked images to the paths vector
 
470
          res = res && ReadUrlBox(file, length_box, &path_file);
 
471
          //path_file=root_dir_+path_file; /// OJOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO
 
472
          v_path_file.push_back(path_file);
 
473
          break;
 
474
        default:
 
475
          res = res && file.Seek(length_box, SEEK_CUR);
 
476
      }
 
477
    }
 
478
    image_info->meta_data.meta_data.push_back(FileSegment(pini,file.GetOffset()-pini));
 
479
    int ind_codestream=0;
 
480
    for (vector<uint16_t>::const_iterator i = v_data_reference.begin(); i!=v_data_reference.end(); i++)
 
481
    {
 
482
        image_info->paths.insert(pair<string, int> (v_path_file[*i-1],ind_codestream));
 
483
        ind_codestream++;
 
484
    }
 
485
    if (image_info->paths.size()>0)
 
486
    {
 
487
        image_info->codestreams.resize(image_info->paths.size());
 
488
        image_info->meta_data_hyperlinks.resize(image_info->paths.size());
 
489
    }
 
490
    // Get image info of the hyperlinked images
 
491
    for (multimap<string, int>::iterator i = image_info->paths.begin(); i != image_info->paths.end() && res; i++)
 
492
    {
 
493
      ImageInfo image_info_hyperlink;
 
494
      res = res && ReadImage((*i).first, &image_info_hyperlink);
 
495
      image_info->coding_parameters = image_info_hyperlink.coding_parameters;
 
496
      image_info->codestreams[(*i).second] = image_info_hyperlink.codestreams.back();
 
497
      image_info->meta_data_hyperlinks[(*i).second] = image_info_hyperlink.meta_data;
 
498
    }
 
499
    return res;
 
500
  }
 
501
 
 
502
  bool FileManager::ReadNlstBox(const File& file, int *num_codestream, int length_box)
 
503
  {
 
504
    bool res = true;
 
505
    // Get the codestream number
 
506
    uint32_t an;
 
507
    while (res && (length_box > 0))
 
508
    {
 
509
      res = res && file.ReadReverse(&an);
 
510
      if ((an >> 24) == 1)
 
511
      {
 
512
        *num_codestream = an & 0x00FFFFFF;
 
513
      }
 
514
      length_box -= 4;
 
515
    }
 
516
    return res;
 
517
  }
 
518
 
 
519
  bool FileManager::ReadFlstBox(const File& file, uint64_t length_box, uint16_t *data_reference)
 
520
  {
 
521
        bool res = true;
 
522
    // Get the path of the hyperlinked image
 
523
    res = res && file.Seek(14, SEEK_CUR);
 
524
    res = res && file.ReadReverse(data_reference);
 
525
 
 
526
    return res;
 
527
  }
 
528
 
 
529
  bool FileManager::ReadUrlBox(const File& file, uint64_t length_box, string *path_file)
 
530
  {
 
531
    bool res = true;
 
532
    // Get the path of the hyperlinked image
 
533
    res = res && file.Seek(4, SEEK_CUR);
 
534
    char path_char[length_box - 4];
 
535
    res = res && file.Read(path_char, length_box - 4);
 
536
    *path_file = path_char;
 
537
    size_t found = path_file->find("file://") + 7;
 
538
    *path_file = path_file->substr(found);
 
539
    //*path_file = path_file->substr(found + 2);
 
540
    // Replace "./" with the root_dir_
 
541
    size_t pos = path_file->find("./");
 
542
    if (pos != string::npos) *path_file = path_file->substr(0, pos) + root_dir_ + path_file->substr(pos + 2);
 
543
 
 
544
    return res;
 
545
  }
 
546
 
 
547
}
 
548