-
Notifications
You must be signed in to change notification settings - Fork 29
/
LFUtilUnpackLytroArchive.m
145 lines (122 loc) · 5.58 KB
/
LFUtilUnpackLytroArchive.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
% LFUtilUnpackLytroArchive - extract white images and other files from a multi-volume Lytro archive
%
% Usage:
% LFUtilUnpackLytroArchive
% LFUtilUnpackLytroArchive( InputPath )
% LFUtilUnpackLytroArchive( InputPath, FirstVolumeFname )
% LFUtilUnpackLytroArchive( [], FirstVolumeFname )
%
% This extracts all the files from all Lytro archives found in the requested path. Archives typically take on names like
% data.C.0, data.C.1 and so forth, and contain white images, metadata and other information.
%
% The function searches for archives recursively, so if there are archives in multiple sub-folders, they will all be
% expanded. The file LFToolbox.json is created to mark completion of the extraction in a folder. Already-expanded
% archives are skipped; delete LFToolbox.json to force re-extraction in a folder.
%
% Based in part on Nirav Patel and Doug Kelley's LFP readers. Thanks to Michael Tao for help and samples for decoding
% Illum imagery.
%
% Inputs -- all are optional :
%
% InputPath : Path to folder containing the archive, default 'Cameras'
% FirstVolumeFname : Name of the first file in the archive, default 'data.C.0'
%
% Example:
%
% LFUtilUnpackLytroArchive
%
% Will extract the contents of all archives in all subfolders of the current folder. If you are working with
% multiple cameras, place each multi-volume archve in its own sub-folder, then call this from the top-level folder
% to expand them all.
%
% User guide: <a href="matlab:which LFToolbox.pdf; open('LFToolbox.pdf')">LFToolbox.pdf</a>
% See also: LFUtilProcessWhiteImages, LFReadLFP, LFUtilExtractLFPThumbs
% Copyright (c) 2013-2020 Donald G. Dansereau
function LFUtilUnpackLytroArchive( InputPath, FirstVolumeFname )
%---Defaults---
InputPath = LFDefaultVal('InputPath','Cameras');
FirstVolumeFname = LFDefaultVal('FirstVolumeFname','data.C.0');
[AllVolumes, BasePath] = LFFindFilesRecursive(InputPath, FirstVolumeFname);
fprintf('Found :\n');
disp(AllVolumes)
%---Consts---
LFPConsts.LFPHeader = hex2dec({'89', '4C', '46', '50', '0D', '0A', '1A', '0A', '00', '00', '00', '01'}); % 12-byte LFPSections header
LFPConsts.SectHeaderLFM = hex2dec({'89', '4C', '46', '4D', '0D', '0A', '1A', '0A'})'; % header for table of contents
LFPConsts.SectHeaderLFC = hex2dec({'89', '4C', '46', '43', '0D', '0A', '1A', '0A'})'; % header for content section
LFPConsts.SecHeaderPaddingLen = 4;
LFPConsts.Sha1Length = 45;
LFPConsts.ShaPaddingLen = 35; % Sha1 codes are followed by 35 null bytes
LFToolboxInfoFname = 'LFToolbox.json';
%---
for( VolumeIdx = 1:length(AllVolumes) )
CurFile = fullfile(BasePath, AllVolumes{VolumeIdx});
OutPath = fileparts(CurFile);
fprintf('Extracting files in "%s"...\n', OutPath);
CurInfoFname = fullfile( OutPath, LFToolboxInfoFname );
if( exist(CurInfoFname, 'file') )
fprintf('Already done, skipping (delete "%s" to force redo)\n\n', CurInfoFname);
continue;
end
while( 1 )
fprintf(' %s...\n', CurFile);
InFile=fopen(CurFile, 'rb');
%---Check for the magic header---
HeaderBytes = fread( InFile, length(LFPConsts.LFPHeader), 'uchar' );
if( ~all( HeaderBytes == LFPConsts.LFPHeader ) )
fclose(InFile);
fprintf( 'Unrecognized file type' );
return
end
%---Confirm headerlength bytes---
HeaderLength = fread(InFile,1,'uint32','ieee-be');
assert( HeaderLength == 0, 'Unexpected length at top-level header' );
%---Read each section---
% This implementation assumes the TOC appears first in each file
clear TOC
while( ~feof(InFile) )
CurSection = ReadSection( InFile, LFPConsts );
if( all( CurSection.SectHeader == LFPConsts.SectHeaderLFM ) )
TOC = LFReadMetadata( CurSection.Data );
else
assert( exist('TOC','var')==1, 'Expected to find table of contents at top of file' );
MatchingSectIdx = find( strcmp( CurSection.Sha1, {TOC.files.dataRef} ) );
CurFname = TOC.files(MatchingSectIdx).name;
CurFname = strrep( CurFname, 'C:\', '' );
CurFname = strrep( CurFname, '\', '__' );
OutFile = fopen( fullfile(OutPath, CurFname), 'wb' );
fwrite( OutFile, CurSection.Data );
fclose(OutFile);
end
end
fclose( InFile );
if( isfield(TOC, 'nextFile') )
CurFile = fullfile(OutPath, TOC.nextFile);
else
break;
end
end
TimeStamp = datestr(now,'ddmmmyyyy_HHMMSS');
GeneratedByInfo = struct('mfilename', mfilename, 'time', TimeStamp, 'VersionStr', LFToolboxVersion);
fprintf( 'Marking completion in "%s"\n\n', CurInfoFname );
LFWriteMetadata( CurInfoFname, GeneratedByInfo );
end
fprintf('Done\n');
end
% --------------------------------------------------------------------
function LFPSect = ReadSection( InFile, LFPConsts )
LFPSect.SectHeader = fread(InFile, length(LFPConsts.SectHeaderLFM), 'uchar')';
Padding = fread(InFile, LFPConsts.SecHeaderPaddingLen, 'uint8'); % skip padding
SectLength = fread(InFile, 1, 'uint32', 'ieee-be');
LFPSect.Sha1 = char(fread(InFile, LFPConsts.Sha1Length, 'uchar')');
Padding = fread(InFile, LFPConsts.ShaPaddingLen, 'uint8'); % skip padding
LFPSect.Data = char(fread(InFile, SectLength, 'uchar'))';
while( 1 )
Padding = fread(InFile, 1, 'uchar');
if( feof(InFile) || (Padding ~= 0) )
break;
end
end
if ~feof(InFile)
fseek( InFile, -1, 'cof'); % rewind one byte
end
end