├── Makefile ├── lfpsplitter.h ├── README_V2 ├── README └── lfpsplitter.c /Makefile: -------------------------------------------------------------------------------- 1 | OBJS = 2 | CC = gcc 3 | CFLAGS = -O3 -Wall 4 | LDFLAGS = 5 | 6 | # gcc only 7 | CCMACHINE = $(shell $(CC) -dumpmachine) 8 | 9 | # On windows + mingw, link winsock2 lib. 10 | ifeq ($(findstring mingw32, $(CCMACHINE)), mingw32) 11 | LDFLAGS += -lws2_32 12 | endif 13 | 14 | .PHONY: all 15 | all: lfpsplitter 16 | 17 | lfpsplitter: lfpsplitter.o $(OBJS) 18 | $(CC) -o $@ lfpsplitter.o $(OBJS) $(CFLAGS) $(LDFLAGS) 19 | 20 | .PHONY: clean 21 | clean: 22 | rm -f $(OBJS) lfpsplitter.o lfpsplitter 23 | -------------------------------------------------------------------------------- /lfpsplitter.h: -------------------------------------------------------------------------------- 1 | #ifndef _LFPSPLITTER_H_ 2 | #define _LFPSPLITTER_H_ 3 | 4 | typedef enum { 5 | LFP_RAW_IMAGE, 6 | LFP_JSON, 7 | LFP_DEPTH_LUT, 8 | LFP_LUT, 9 | LFP_JPEG, 10 | LFP_BLOCK_OF_IMAGES 11 | } section_type; 12 | 13 | typedef struct lfp_section { 14 | section_type type; 15 | char typecode[4]; 16 | int len; 17 | char sha1[46]; // including null termination 18 | char *name; 19 | char *data; 20 | struct lfp_section *next; 21 | } lfp_section_t, *lfp_section_p; 22 | 23 | typedef struct lfp_file { 24 | char *filename; 25 | char *data; 26 | int len; 27 | int num_images; 28 | lfp_section_p table; 29 | lfp_section_p sections; 30 | } lfp_file_t, *lfp_file_p; 31 | 32 | #endif /* _LFPSPLITTER_H_ */ 33 | -------------------------------------------------------------------------------- /README_V2: -------------------------------------------------------------------------------- 1 | In December 2012 Lytro released a software upgrade that supports 2 | perspective shift viewing and "living filters". This entailed a 3 | change to the contents of .lfp files as described below. 4 | ================================================================ 5 | 6 | The Lytro Version 2 software generates three .lfp files instead of two 7 | as in Version 1. These files are: 8 | 9 | 1. IMG_nnnn.lfp 10 | 11 | This file seems to be pretty much the same as Version 1. I have 12 | not done a full analysis, however. 13 | 14 | 2. IMG_nnnn-dm.lfp 15 | 16 | This file is new in Version 2. It contains an expanded depth 17 | map (330 x 330) as well as a confidence map of the same 18 | dimensions. I will wait for someone else to explain what 19 | the confidence map is used for. The depth map represents 20 | lambda values, as in Version 1, but at a much finer 21 | granularity than in Version 1. 22 | 23 | 3. IMG_nnnn-stk.lfp 24 | 25 | A file with this name was also generated by Lytro Version 1 software, 26 | but with the Version 2 format the contents have changed. The most 27 | significant difference is that the image stacks are encoded as H264 frame 28 | sequences. The -stk.lfp file may contain one or two image stacks (H264 29 | frame sequences), depending on whether the user has performed 30 | additional processing for shift perspective viewing using the 31 | option provided in the Lytro processing software. 32 | 33 | An example of running the new lfpsplitter on Lytro files generated 34 | with Lytro's version 2 software is shown below. 35 | 36 | $ ./lfpsplitter IMG_0008.lfp 37 | Saved IMG_0008_table.json 38 | Saved IMG_0008_imageRef0.raw 39 | Saved IMG_0008_metadataRef0.json 40 | Saved IMG_0008_privateMetadataRef1.json 41 | 42 | $ ./lfpsplitter IMG_0008-dm.lfp 43 | Saved IMG_0008-dm_table.json 44 | Saved IMG_0008-dm_lut_depth.txt 45 | Saved IMG_0008-dm_lut_confidence.txt 46 | 47 | $ ./lfpsplitter IMG_0008-stk.lfp 48 | Saved IMG_0008-stk_table.json 49 | Saved IMG_0008-stk_blockOfImagesRef_00.h264 50 | Saved IMG_0008-stk_lut_depth.txt 51 | Saved IMG_0008-stk_blockOfImagesRef_01.h264 52 | 53 | The example shown above was run on an image where 54 | perspective shift processing had been performed. If it 55 | had not been performed, only one .h264 file would 56 | have been output for IMG_0008-stk.lfp. 57 | 58 | Note tha lfpsplitter does NOT decode the H264 blocks into individual 59 | images. There are legal issues swirling around H264 decoding, so you 60 | will need to find another utility to accomplish this. You might 61 | try ffmpeg (ffmpeg.org). Using that utility, you could try the 62 | following command line to generate JPEGs: 63 | 64 | ffmpeg -format h265 -i IMG_0008-stk_blockOfImagesRef_00.h264 65 | -an -qscale 1 IMG_0008-stk_blockOfImagesRef_00_%04d.jpg 66 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | Platform independent tools for working with Lytro LFP files 2 | =========================================================== 3 | 4 | Lytro has not announced much about their file formats other than that they 5 | have software for OS X and will have Windows supported in 2012. To enable 6 | support for other platforms, it will be useful to develop open source software 7 | to process their files. 8 | 9 | This tool supports both the large raw files that come from the Lytro camera 10 | and the compressed files that the desktop software produces for web display. 11 | 12 | Note: The description below refers to .lfp file format for files generated 13 | using Lytro's Version 1 processing software. See README_V2 for a description 14 | of .lfp format changes as of Lytro's December 2012 update (Version 2). 15 | 16 | .lfp file format 17 | ---------------- 18 | 19 | The file itself is formatted as follows. First, a header: 20 | 21 | # magic 12 byte header (LFP) 22 | 89 4C 46 50 0D 0A 1A 0A 00 00 00 01 23 | # 4 byte length (0, since there is nothing in this section) 24 | 00 00 00 00 25 | 26 | After this are a number of sections. The data in the first is plain text 27 | JSON table of contents describing what the rest of the sections in the file 28 | contain. The remaining sections can be additional metadata, a depth lookup 29 | table, compressed jpg images, or raw sensor data depending on the file. 30 | The sections are formatted as follows: 31 | 32 | # magic 12 byte header (containing a type like LFM or LFC) 33 | 89 4C 46 4D 0D 0A 1A 0A 00 00 00 00 34 | # 4 byte length, not including header, sha1, or null padding 35 | 00 00 07 A7 36 | # 45 bytes of sha1 hash as hex in ascii 37 | 73 68 61 31 ... 38 | # 35 bytes of null padding 39 | 00 00 00 00 ... 40 | # the data of length previously specified 41 | 7B 22 70 69 ... 42 | # 0 or more bytes of null padding 43 | 00 00 00 00 ... 44 | 45 | .lfp web files 46 | -------------- 47 | 48 | The Lytro desktop app exports compressed representations of the light field 49 | captured by the Lytro camera to reduce file times and rendering requirements 50 | for web display. The .lfp files are simply a set of JPEG files representing 51 | the unique visually interesting sections of the light field. That is, a set in 52 | which each image shows a different area in focus. It appears to do so 53 | dynamically, picking the minimum number of images necessary to show all 54 | *focusable* objects in narrow depths of field. 55 | 56 | These images are stored along with their estimated depths and a depth lookup 57 | table for the image. This allows for HTML5 and Flash applications in which the 58 | user clicks on a region of the image, the value of that region is looked up, 59 | and the depth image closest to that value is displayed. 60 | 61 | .lfp raw files 62 | -------------- 63 | The files that come directly from the camera are roughly 16MB, made primarily 64 | of one section which is a raw Bayer array of the 3280 x 3280 pixel sensor. 65 | There are also two metadata files, one containing detailed information about 66 | the format of the captured image, and the other containing serial numbers. 67 | 68 | lfpsplitter 69 | ----------- 70 | 71 | lfpsplitter is a commandline tool that reads in a .lfp file and splits it into 72 | a plaintext metadata file, a plaintext listing of the depth lookup table, and 73 | the component jpgs. 74 | 75 | make 76 | gcc -O3 -Wall -c -o lfpsplitter.o lfpsplitter.c 77 | gcc -o lfpsplitter lfpsplitter.o -O3 -Wall 78 | 79 | ./lfpsplitter IMG_0001.lfp 80 | Saved IMG_0001_table.json 81 | Saved IMG_0001_imageRef0.raw 82 | Saved IMG_0001_metadataRef.json 83 | Saved IMG_0001_privateMetadataRef.json 84 | 85 | ./lfpsplitter IMG_0001-stk.lfp 86 | Saved IMG_0001-stk_table.json 87 | Saved IMG_0001-stk_depth.txt 88 | Saved IMG_0001-stk_0.jpg 89 | Saved IMG_0001-stk_1.jpg 90 | Saved IMG_0001-stk_2.jpg 91 | Saved IMG_0001-stk_3.jpg 92 | 93 | -------------------------------------------------------------------------------- /lfpsplitter.c: -------------------------------------------------------------------------------- 1 | /* lfpsplitter - Splits the .lfp files generated by Lytro's desktop app into 2 | * .jpg, .json, and .txt files in a hopefully platform independent way 3 | * 4 | * Copyright (c) 2011, Nirav Patel 5 | * 6 | * Permission to use, copy, modify, and/or distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | * 18 | * Modifications for Lytro Version 2 files made on 1/13/2013 by 19 | * Elissa Weidaw. 20 | */ 21 | 22 | #include 23 | #include 24 | #include 25 | #ifdef _WIN32 26 | #include 27 | typedef unsigned int uint32_t; 28 | #else 29 | #include 30 | #endif 31 | #include "lfpsplitter.h" 32 | 33 | #define SHA1_LENGTH 45 34 | #define MAGIC_LENGTH 12 35 | #define BLANK_LENGTH 35 36 | #define STRING_LENGTH 256 37 | #define LUT_DIM_V1 20 38 | #define LUT_DIM_V2 330 39 | 40 | #ifdef _MSC_VER 41 | #define snprintf _snprintf 42 | #endif 43 | 44 | // TODO: read directly from the file instead of copying to a string 45 | // since camera backup files can be in the hundreds of megabytes 46 | static lfp_file_p lfp_create(const char *filename) 47 | { 48 | FILE *fp; 49 | lfp_file_p lfp = (lfp_file_p)calloc(1, sizeof(lfp_file_t)); 50 | if (!lfp) { 51 | return NULL; 52 | } 53 | 54 | if (!(fp = fopen(filename, "rb"))) { 55 | return NULL; 56 | } 57 | 58 | fseek(fp, 0, SEEK_END); 59 | lfp->len = ftell(fp); 60 | fseek(fp, 0, SEEK_SET); 61 | lfp->data = (char*)malloc(lfp->len); 62 | 63 | lfp->len = fread(lfp->data, 1, lfp->len, fp); 64 | fclose(fp); 65 | 66 | return lfp; 67 | } 68 | 69 | static int lfp_file_check(lfp_file_p lfp) 70 | { 71 | char magic[8] = {0x89, 0x4C, 0x46, 0x50, 0x0D, 0x0A, 0x1A, 0x0A}; 72 | if (lfp->len > sizeof(magic) && memcmp(lfp->data, magic, sizeof(magic)) == 0) return 1; 73 | return 0; 74 | } 75 | 76 | static lfp_section_p parse_section(char **lfp, int *in_len) 77 | { 78 | char *ptr = *lfp; 79 | int len = *in_len; 80 | lfp_section_p section = calloc(1,sizeof(lfp_section_t)); 81 | if (!section) return NULL; 82 | 83 | // There may be some null region between sections 84 | while (*ptr == '\0' && len) { 85 | ptr++; 86 | len--; 87 | } 88 | 89 | if (len <= MAGIC_LENGTH+sizeof(uint32_t)+SHA1_LENGTH+BLANK_LENGTH) { 90 | free(section); 91 | return NULL; 92 | } 93 | 94 | // Copy the magic type 95 | memcpy(section->typecode, ptr, 4); 96 | // Move past the magic and the first 4 bytes of 0s 97 | ptr += MAGIC_LENGTH; 98 | len -= MAGIC_LENGTH; 99 | 100 | // the length is stored as a big endian unsigned 32 bit int 101 | section->len = ntohl(*(uint32_t *)ptr); 102 | ptr += sizeof(uint32_t); 103 | len -= sizeof(uint32_t); 104 | 105 | // copy and move past the sha1 string and the 35 byte empty space 106 | memcpy(section->sha1, ptr, SHA1_LENGTH); 107 | ptr += SHA1_LENGTH+BLANK_LENGTH; 108 | len -= SHA1_LENGTH+BLANK_LENGTH; 109 | 110 | // make sure there exists as much data as the header claims 111 | if (len < section->len) { 112 | free(section); 113 | return NULL; 114 | } 115 | 116 | // just directly reference the existing buffer 117 | section->data = ptr; 118 | 119 | ptr += section->len; 120 | len -= section->len; 121 | 122 | *lfp = ptr; 123 | *in_len = len; 124 | 125 | return section; 126 | } 127 | 128 | static char *depth_string(const char *data, int *datalen, int len) 129 | { 130 | // make sure there is enough space for the ascii formatted floats 131 | int filelen = 20*len/4; 132 | char *depth = (char*)malloc(filelen); 133 | char *start = depth; 134 | int i = 0; 135 | 136 | if (!depth) return NULL; 137 | depth[0] = '\0'; 138 | 139 | for (i = 0; i < len/4; i++) { 140 | char val[20]; 141 | int vallen = 0; 142 | snprintf(val, 20, "%f\n",*(float *)(data+i*4)); 143 | vallen = strlen(val); 144 | strncpy(depth, val, vallen); 145 | depth += vallen; 146 | } 147 | 148 | *datalen = depth-start; 149 | 150 | return start; 151 | } 152 | 153 | static char *converted_image(const unsigned char *data, int *datalen, int len) 154 | { 155 | int filelen = 4*len/3; 156 | const unsigned char *ptr = data; 157 | unsigned short *image = (unsigned short*)malloc(filelen*sizeof(short)); 158 | unsigned short *start = image; 159 | 160 | if (!image) return NULL; 161 | // Turn the 12 bits per pixel packed array into 16 bits per pixel 162 | // to make it easier to import into other libraries 163 | while (ptr < data+len) { 164 | *image++ = (*ptr << 8) | (*(ptr+1) & 0xF0); 165 | *image++ = ((*(ptr+1) & 0x0F) << 12) | (*(ptr+2) << 4); 166 | 167 | ptr += 3; 168 | } 169 | 170 | *datalen = filelen; 171 | 172 | return (char *)start; 173 | } 174 | 175 | static int save_data(const char *data, int len, const char *filename) 176 | { 177 | FILE *fp; 178 | 179 | if (!(fp = fopen(filename, "wb"))) { 180 | fprintf(stderr, "Failed to open %s for writing\n", filename); 181 | return 0; 182 | } 183 | 184 | if (fwrite(data, 1, len, fp) != len) { 185 | fprintf(stderr, "Failed to write %s\n", filename); 186 | return 0; 187 | } 188 | 189 | fclose(fp); 190 | 191 | return 1; 192 | } 193 | 194 | // Try to figure out if the data represents an image, json, raw data, etc 195 | static void lfp_identify_section(lfp_file_p lfp, lfp_section_p section) 196 | { 197 | char jpeg[10] = {0xFF, 0xD8, 0xFF, 0xE0, 0x00, 0x10, 0x4A, 0x46, 0x49, 0x46}; 198 | char *ptr = NULL; 199 | int quotecount = 0; 200 | section->name = (char*)malloc(STRING_LENGTH); 201 | 202 | // Find the sha1 in the table of contents 203 | if ((ptr = strstr(lfp->table->data, section->sha1))) { 204 | // Move backwards to the corresponding name 205 | while (quotecount < 3 && (ptr-- > lfp->table->data)) 206 | if (*ptr == '"') quotecount++; 207 | 208 | // Read the name if we can 209 | if ((!quotecount == 3) || (sscanf(ptr, "\"%255[^\"]\"", section->name) != 1)) 210 | strcpy(section->name, "unknown"); 211 | } 212 | 213 | // Test for Lytro Version 1 depth map 214 | if (section->len == LUT_DIM_V1 * LUT_DIM_V1 * 4) { 215 | section->type = LFP_DEPTH_LUT; 216 | strcpy(section->name, "depth"); 217 | return; 218 | } 219 | 220 | // Test for Lytro Version 2 LUT (depth or confidence) map 221 | if (section->len == LUT_DIM_V2 * LUT_DIM_V2 * 4) { 222 | section->type = LFP_LUT; 223 | strcpy(section->name, "lut"); 224 | return; 225 | } 226 | 227 | // Check for the magic bytes to see if its a jpg 228 | if ((section->len > sizeof(jpeg)) && 229 | (memcmp(section->data, jpeg, sizeof(jpeg)) == 0)) { 230 | section->type = LFP_JPEG; 231 | strcpy(section->name, "image"); 232 | return; 233 | } 234 | 235 | // Check for h264 block 236 | if (strcmp(section->name, "blockOfImagesRef") == 0) { 237 | section->type = LFP_BLOCK_OF_IMAGES; 238 | return; 239 | } 240 | 241 | // Assume anything else that isn't called imageRef is plain text json 242 | if (strcmp(section->name, "imageRef")) 243 | section->type = LFP_JSON; 244 | } 245 | 246 | static void lfp_parse_sections(lfp_file_p lfp) 247 | { 248 | char *ptr = lfp->data; 249 | int len = lfp->len; 250 | 251 | // Move past the first header 252 | ptr += MAGIC_LENGTH+sizeof(uint32_t); 253 | len -= MAGIC_LENGTH+sizeof(uint32_t); 254 | 255 | // Assume the first section is always the table of contents 256 | lfp->table = parse_section(&ptr, &len); 257 | lfp->table->type = LFP_JSON; 258 | lfp->table->name = "table"; 259 | 260 | lfp_section_p cur_section = NULL; 261 | while (len > 0) { 262 | lfp_section_p new_section = parse_section(&ptr, &len); 263 | if (!new_section) break; 264 | 265 | lfp_identify_section(lfp, new_section); 266 | 267 | if (!lfp->sections) lfp->sections = new_section; 268 | else if (cur_section) cur_section->next = new_section; 269 | cur_section = new_section; 270 | } 271 | } 272 | 273 | static void lfp_save_sections(lfp_file_p lfp) 274 | { 275 | char name[STRING_LENGTH]; 276 | lfp_section_p section = lfp->sections; 277 | int jpeg = 0, raw = 0, text = 0, image_block = 0, lut = 0; 278 | char *buf; 279 | int buflen = 0; 280 | 281 | // Save the plaintext json metadata 282 | snprintf(name, STRING_LENGTH, "%s_%s.json", lfp->filename, lfp->table->name); 283 | if (save_data(lfp->table->data, lfp->table->len, name)) 284 | printf("Saved %s\n", name); 285 | 286 | while (section != NULL) { 287 | switch (section->type) { 288 | case LFP_RAW_IMAGE: 289 | buf = converted_image((unsigned char *)section->data, &buflen, section->len); 290 | if (buf) { 291 | snprintf(name, STRING_LENGTH, "%s_%s%d.raw", lfp->filename, section->name, raw++); 292 | if (save_data(buf, buflen, name)) 293 | printf("Saved %s\n", name); 294 | free(buf); 295 | } 296 | break; 297 | 298 | case LFP_JSON: 299 | snprintf(name, STRING_LENGTH, "%s_%s%d.json", lfp->filename, section->name, text++); 300 | if (save_data(section->data, section->len, name)) 301 | printf("Saved %s\n", name); 302 | break; 303 | 304 | case LFP_DEPTH_LUT: 305 | // Parse the depth lookup table and save as plaintext 306 | buf = depth_string(section->data, &buflen, section->len); 307 | if (buf) { 308 | snprintf(name, STRING_LENGTH, "%s_%s.txt", lfp->filename, section->name); 309 | if (save_data(buf, buflen, name)) 310 | printf("Saved %s\n", name); 311 | free(buf); 312 | } 313 | break; 314 | 315 | // Lytro Version 2 LUT - depth or confidence map 316 | case LFP_LUT: 317 | // Parse the LUT and save as plaintext 318 | buf = depth_string(section->data, &buflen, section->len); 319 | if (buf) { 320 | if (lut++ == 0) { 321 | snprintf(name, STRING_LENGTH, "%s_%s_depth.txt", lfp->filename, section->name); 322 | } else { 323 | snprintf(name, STRING_LENGTH, "%s_%s_confidence.txt", lfp->filename, section->name); 324 | } 325 | if (save_data(buf, buflen, name)){ 326 | printf("Saved %s\n", name); 327 | } 328 | free(buf); 329 | } 330 | break; 331 | 332 | case LFP_JPEG: 333 | snprintf(name, STRING_LENGTH, "%s_%.2d.jpg", lfp->filename, jpeg++); 334 | if (save_data(section->data, section->len, name)) 335 | printf("Saved %s\n", name); 336 | break; 337 | 338 | // Lytro Version 2 H264 block 339 | case LFP_BLOCK_OF_IMAGES: 340 | snprintf(name, STRING_LENGTH, "%s_%s_%.2d.h264", lfp->filename, section->name, image_block++); 341 | if (save_data(section->data, section->len, name)) 342 | printf("Saved %s\n", name); 343 | break; 344 | } 345 | 346 | section = section->next; 347 | } 348 | } 349 | 350 | static void lfp_close(lfp_file_p lfp) 351 | { 352 | if (lfp) { 353 | lfp_section_p section = lfp->sections; 354 | 355 | if (lfp->data) free(lfp->data); 356 | if (lfp->filename) free(lfp->filename); 357 | while (section) { 358 | lfp_section_p cur = section; 359 | section = section->next; 360 | if (cur->name) free(cur->name); 361 | free(cur); 362 | } 363 | memset(lfp, '\0', sizeof(lfp_file_t)); 364 | } 365 | } 366 | 367 | int main(int argc, char *argv[]) 368 | { 369 | char *period = NULL; 370 | lfp_file_p lfp = NULL; 371 | 372 | if (argc < 2) { 373 | fprintf(stderr, "Usage: lfpsplitter file.lfp\n"); 374 | return 1; 375 | } 376 | 377 | if (!(lfp = lfp_create(argv[1]))) { 378 | fprintf(stderr, "Failed to open file %s\n", argv[1]); 379 | lfp_close(lfp); 380 | return 1; 381 | } 382 | 383 | if (!lfp_file_check(lfp)) { 384 | fprintf(stderr, "File %s does not look like an lfp\n", argv[1]); 385 | lfp_close(lfp); 386 | return 1; 387 | } 388 | 389 | // save the first part of the filename to name the jpgs later 390 | if (!(lfp->filename = strdup(argv[1]))) { 391 | lfp_close(lfp); 392 | return 1; 393 | } 394 | period = strrchr(lfp->filename,'.'); 395 | if (period) *period = '\0'; 396 | 397 | lfp_parse_sections(lfp); 398 | 399 | lfp_save_sections(lfp); 400 | 401 | lfp_close(lfp); 402 | return 0; 403 | } 404 | --------------------------------------------------------------------------------