brought to you by Deparment of Optics & Acoustics

decoding H.264 frames

The following code requires referencing the viewer instead of the library and does no error checking.

LightFieldPackage package = new LightFieldPackage(File.OpenRead(@"path to the file\stack.lfp")); LightFieldComponent metadata = package.GetMetadata().First(); Json.Master master = new Json.Master(); master.LoadFromJson(metadata.GetDataAsString()); if (master.Picture != null) { RefocusStackAcceleration refocusStack = new PictureMetadata(master.Picture).RefocusStack; if (refocusStack != null) { if (refocusStack.HasImages) { foreach (var image in refocusStack.Images) { LightFieldComponent imageComponent = package.GetComponent(image.Reference).First(); File.WriteAllBytes("λ = " + image.Lambda + ".jpg", imageComponent.Data); } } // Requires referencing LytroCompatibleViewer instead of LytroCompatibleLibrary if (refocusStack.HasBlockImages) { int frameIndex = 0; BlockImageDecoder blockDecoder = new BlockImageDecoder(); blockDecoder.BlockImageDecoded += (width, height, format, palette, data, stride) => { BitmapSource decodedFrame = BitmapSource.Create(width, height, 96, 96, format, palette, data, stride); JpegBitmapEncoder jpeg = new JpegBitmapEncoder(); jpeg.Frames.Add(BitmapFrame.Create(decodedFrame)); using (Stream file = File.OpenWrite("λ = " + refocusStack.BlockImages[frameIndex++].Lambda + ".jpg")) jpeg.Save(file); return true; // continue decoding }; LightFieldComponent blockImageComponent = package.GetComponent(refocusStack.BlockImages.Reference).First(); blockDecoder.Decode(blockImageComponent.Data); } } }

To get the parallax shift frames, use the same code, just use ParallaxStackAcceleration parallaxStack = new PictureMetadata(master.Picture).ParallaxStack; instead of the refocus stack.

desktop LytroNetClient

The LytroNetClientPortableBase inheritors must basically implement a single method: GetStream which is called whenever data needs to be transferred and the previously returned stream, if any, is no longer usable (e.g. the connection was lost). A simple implementation for platforms with TcpClient:

public class LytroNetClient : LytroNetClientPortableBase { private Stream _stream; private TcpClient _client; protected override Stream GetStream() { if (_stream == null || !_stream.CanRead || !_stream.CanWrite) { _client = new TcpClient(); _client.Connect("10.100.1.1", 5678); _stream = _client.GetStream(); } return _stream; } protected override void OnException(Exception e, Stream stream) { if (_client != null) _client.Close(); } }

(or just reference the communicator assembly instead, which includes one with async support)

decoding YUY2 bitmaps

The following code does no error checking. You can pass the result to BitmapSource.Create(width, height, 96, 96, PixelFormats.Bgr24, null, bgr24, width * 3).

private static byte[] YUY2toBGR24(byte[] yuy2, int width, int height) { byte[] bgr24 = new byte[width * height * 3]; if (width % 2 != 0) // you can get more fancy handling the missing V sample width--; // this code just ignores the whole YV pair for (int y = 0; y < height; y++) { int width2y = width * 2 * y; int width3y = width * 3 * y; for (int x = 0; x < width; x++) { byte Y = yuy2[width2y + x * 2]; byte U = yuy2[width2y + (x / 2) * 4 + 1]; byte V = yuy2[width2y + (x / 2) * 4 + 3]; YUVtoRGB(Y, U, V, out bgr24[width3y + x * 3 + 2], out bgr24[width3y + x * 3 + 1], out bgr24[width3y + x * 3 + 0]); } } return bgr24; } private static void YUVtoRGB(byte Y, byte U, byte V, out byte R, out byte G, out byte B) { int C = Y - 16; int D = U - 128; int E = V - 128; R = Coerce((298 * C + 409 * E + 128) >> 8); G = Coerce((298 * C - 100 * D - 208 * E + 128) >> 8); B = Coerce((298 * C + 516 * D + 128) >> 8); } private static byte Coerce(int value) { return value < 0 ? (byte)0 : value > 255 ? (byte)255 : (byte)value; }

subaperture image

Code required to render single subaperture image, with no error checking:

private static BitmapSource RenderSubaperture(string path) { LightFieldPackage package = new LightFieldPackage(File.OpenRead(path)); FieldImage field = FieldImage.From(package); XYImage subaperture = field.GetSubapertureImage(0, 0); return ToBitmapSource(subaperture, width, height); } private static unsafe BitmapSource ToBitmapSource(ISampled2D<ColorRgba128Float> image) { int width = image.Width; int height = image.Height; ColorRgba128Float[] data = new ColorRgba128Float[width * height]; for (int y = 0; y < height; y++) for (int x = 0; x < width; x++) data[y * width + x] = image[x, y]; fixed (void* pData = data) return BitmapSource.Create(width, height, 96, 96, PixelFormats.Rgba128Float, null, (IntPtr)pData, data.Length * sizeof(ColorRgba128Float), width * sizeof(ColorRgba128Float)); }

You will need references to PresentationCore and WindowsBase assemblies and allow unsafe code to get the BitmapSource out.

Disclaimer: Jan Kučera and miloush.net are not affiliated with or endorsed by Lytro, Inc.