Skip to content

Commit

Permalink
Merge pull request #4 from eweidaw/master
Browse files Browse the repository at this point in the history
Handle files from Lytro V2 format, by eweidaw, r=nrpatel
  • Loading branch information
eclecticc committed Jan 17, 2013
2 parents 4bf7bc9 + 13f493c commit 1204b0c
Show file tree
Hide file tree
Showing 4 changed files with 118 additions and 5 deletions.
4 changes: 4 additions & 0 deletions README
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ to process their files.
This tool supports both the large raw files that come from the Lytro camera
and the compressed files that the desktop software produces for web display.

Note: The description below refers to .lfp file format for files generated
using Lytro's Version 1 processing software. See README_V2 for a description
of .lfp format changes as of Lytro's December 2012 update (Version 2).

.lfp file format
----------------

Expand Down
65 changes: 65 additions & 0 deletions README_V2
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
In December 2012 Lytro released a software upgrade that supports
perspective shift viewing and "living filters". This entailed a
change to the contents of .lfp files as described below.
================================================================

The Lytro Version 2 software generates three .lfp files instead of two
as in Version 1. These files are:

1. IMG_nnnn.lfp

This file seems to be pretty much the same as Version 1. I have
not done a full analysis, however.

2. IMG_nnnn-dm.lfp

This file is new in Version 2. It contains an expanded depth
map (330 x 330) as well as a confidence map of the same
dimensions. I will wait for someone else to explain what
the confidence map is used for. The depth map represents
lambda values, as in Version 1, but at a much finer
granularity than in Version 1.

3. IMG_nnnn-stk.lfp

A file with this name was also generated by Lytro Version 1 software,
but with the Version 2 format the contents have changed. The most
significant difference is that the image stacks are encoded as H264 frame
sequences. The -stk.lfp file may contain one or two image stacks (H264
frame sequences), depending on whether the user has performed
additional processing for shift perspective viewing using the
option provided in the Lytro processing software.

An example of running the new lfpsplitter on Lytro files generated
with Lytro's version 2 software is shown below.

$ ./lfpsplitter IMG_0008.lfp
Saved IMG_0008_table.json
Saved IMG_0008_imageRef0.raw
Saved IMG_0008_metadataRef0.json
Saved IMG_0008_privateMetadataRef1.json

$ ./lfpsplitter IMG_0008-dm.lfp
Saved IMG_0008-dm_table.json
Saved IMG_0008-dm_lut_depth.txt
Saved IMG_0008-dm_lut_confidence.txt

$ ./lfpsplitter IMG_0008-stk.lfp
Saved IMG_0008-stk_table.json
Saved IMG_0008-stk_blockOfImagesRef_00.h264
Saved IMG_0008-stk_lut_depth.txt
Saved IMG_0008-stk_blockOfImagesRef_01.h264

The example shown above was run on an image where
perspective shift processing had been performed. If it
had not been performed, only one .h264 file would
have been output for IMG_0008-stk.lfp.

Note tha lfpsplitter does NOT decode the H264 blocks into individual
images. There are legal issues swirling around H264 decoding, so you
will need to find another utility to accomplish this. You might
try ffmpeg (ffmpeg.org). Using that utility, you could try the
following command line to generate JPEGs:

ffmpeg -format h265 -i IMG_0008-stk_blockOfImagesRef_00.h264
-an -qscale 1 IMG_0008-stk_blockOfImagesRef_00_%04d.jpg
50 changes: 46 additions & 4 deletions lfpsplitter.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* Modifications for Lytro Version 2 files made on 1/13/2013 by
* Elissa Weidaw.
*/

#include <stdio.h>
Expand All @@ -31,6 +34,8 @@ typedef unsigned int uint32_t;
#define MAGIC_LENGTH 12
#define BLANK_LENGTH 35
#define STRING_LENGTH 256
#define LUT_DIM_V1 20
#define LUT_DIM_V2 330

#ifdef _MSC_VER
#define snprintf _snprintf
Expand Down Expand Up @@ -205,22 +210,35 @@ static void lfp_identify_section(lfp_file_p lfp, lfp_section_p section)
strcpy(section->name, "unknown");
}

// Hard coded to assume that the 20x20 LUT is 1600 bytes
if (section->len == 1600) {
// Test for Lytro Version 1 depth map
if (section->len == LUT_DIM_V1 * LUT_DIM_V1 * 4) {
section->type = LFP_DEPTH_LUT;
strcpy(section->name, "depth");
return;
}

// Test for Lytro Version 2 LUT (depth or confidence) map
if (section->len == LUT_DIM_V2 * LUT_DIM_V2 * 4) {
section->type = LFP_LUT;
strcpy(section->name, "lut");
return;
}

// Check for the magic bytes to see if its a jpg
if ((section->len > sizeof(jpeg)) &&
(memcmp(section->data, jpeg, sizeof(jpeg)) == 0)) {
section->type = LFP_JPEG;
strcpy(section->name, "image");
return;
}

// Check for h264 block
if (strcmp(section->name, "blockOfImagesRef") == 0) {
section->type = LFP_BLOCK_OF_IMAGES;
return;
}

// Assume anything that isn't called imageRef is plain text json
// Assume anything else that isn't called imageRef is plain text json
if (strcmp(section->name, "imageRef"))
section->type = LFP_JSON;
}
Expand Down Expand Up @@ -256,7 +274,7 @@ static void lfp_save_sections(lfp_file_p lfp)
{
char name[STRING_LENGTH];
lfp_section_p section = lfp->sections;
int jpeg = 0, raw = 0, text = 0;
int jpeg = 0, raw = 0, text = 0, image_block = 0, lut = 0;
char *buf;
int buflen = 0;

Expand Down Expand Up @@ -293,12 +311,36 @@ static void lfp_save_sections(lfp_file_p lfp)
free(buf);
}
break;

// Lytro Version 2 LUT - depth or confidence map
case LFP_LUT:
// Parse the LUT and save as plaintext
buf = depth_string(section->data, &buflen, section->len);
if (buf) {
if (lut++ == 0) {
snprintf(name, STRING_LENGTH, "%s_%s_depth.txt", lfp->filename, section->name);
} else {
snprintf(name, STRING_LENGTH, "%s_%s_confidence.txt", lfp->filename, section->name);
}
if (save_data(buf, buflen, name)){
printf("Saved %s\n", name);
}
free(buf);
}
break;

case LFP_JPEG:
snprintf(name, STRING_LENGTH, "%s_%.2d.jpg", lfp->filename, jpeg++);
if (save_data(section->data, section->len, name))
printf("Saved %s\n", name);
break;

// Lytro Version 2 H264 block
case LFP_BLOCK_OF_IMAGES:
snprintf(name, STRING_LENGTH, "%s_%s_%.2d.h264", lfp->filename, section->name, image_block++);
if (save_data(section->data, section->len, name))
printf("Saved %s\n", name);
break;
}

section = section->next;
Expand Down
4 changes: 3 additions & 1 deletion lfpsplitter.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ typedef enum {
LFP_RAW_IMAGE,
LFP_JSON,
LFP_DEPTH_LUT,
LFP_JPEG
LFP_LUT,
LFP_JPEG,
LFP_BLOCK_OF_IMAGES
} section_type;

typedef struct lfp_section {
Expand Down

0 comments on commit 1204b0c

Please sign in to comment.